android - แปลรวมๆเรื่อง Fragment

สรุป Android Fragment ภาษาไทย


  • Fragment จะแสดงถึงพฤติกรรม พูดง่ายๆมันเหมือนส่วนหนึ่งของ user interface ใน activity.
  • แต่ fragment จะต้องฝังอยู่ใน activity
  • จัดเป็น "sub activity" ที่สามารถนำมา reuse ใช้ใน Activity อื่น
  • มี view layout ของตัวมันเอง , มีวงจรชีวิตของตัวเอง (fragment lifecycle)
  • คุณสามารถ include one fragment ใน multiple activities
  • คุณสามารถจัดกลุ่มของ multiple fragments ใน sigle activity เพื่อสร้าง multi-pane UI 
  • คุณอาจคิดว่า fragment เป็นชิ้นส่วนแต่ละชิ้นของ activity .. ก็ถูก :P
  • มีการรับ user input จาก Event ของตัวมันเอง
  • ถ้า Host activity paused , destroyed ทุก fragments ด้านใน ก็ paused , destroyed เช่นกัน
  • ในขณะที่ activity running มันจะอยู่ใน resumed state คุณสามารถจัดการแต่ละ fragment อย่างอิสระ เช่น add/remove มัน
  • เหตุการณ์จะเกิดขึ้นร่วมกับ activity และ other fragments และ activity
  • fragment สามารถเก็บ state ของพวกเขาเมื่อ add ไปยัง activity's back stack
  • นอกจากนี้คุณอาจใช้ fragment โดยไม่มี UI เรียกว่าเป็น invisible worker สำหรับ activity
  • lifecycle ของมันจะเกิดขึ้นพร้อม activity lifecycle ของ host activity ที่มันอยู่
  • สามารถ add , remove , replace ขณะที่ activity running แต่จะนุ่มนวลกว่าการ startActivity
  • เมื่อ perform fragment transaction สามารถ add มันไปยัง back stack ที่จัดการโดย Activity
  • แต่ละ back stack entry ใน activity คือ record ของ fragment transaction ที่เกิดขึ้น
  • user สามารถ reverse fragment transaction (navigate backwards), โดยการกดปุ่ม Back
  • เมื่อคุณ add fragment ไปยัง activity layout มันอาศัยอยู่ใน ViewGroup ภายใน activity view hierarchy
  • สามารถ insert fragment ไปยัง activity layout โดยประกาศ fragment ใน activity's layout file 
  • หรือจากทาง application code โดยการ Add มันไปยัง ViewGroup ที่มีอยู่




Design Philosophy
  • Android แนะนำ fragment ใน android 3.0(API level11) 
  • ส่วนใหญ่จะรองรับ UI แบบ dynamic และ flexile designs บนหน้าจอขนาดใหญ่
  • มีการรักษาการเปลี่ยนแปลงเหล่านั้นใน back stack ที่จัดการโดย Activty

fragments สามารถรวมกันใน one activity สำหรับ tablet design
ในขณะที่ handset design จะแสดงทีละ Fragment และเปิด activity B


tablet-sized  : สามารถฝัง 2 fragment ใน Activity A เนื่องจากมีพื้นที่เหลือใช้เยอะ
handset-sized :  มีพื้นที่น้อยในหน้าแรกจึงเก็บไว้แค่ ActivityA  โดยมี Fragment A อยู่ภายใน
เมื่อเลือก article มันจะ start Activity B  โดยมี Fragment B อยู่ภายใน





" Fragment defines its own layout 
  and its own behavior with its own lifecycle callbacks "
ดังนั้น ! การออกแบบควรคำนึงถึงการ reuse 
และหลีกเลี่ยงการจัดการกับ fragment จาก another fragment






You should implement at least the following lifecycle methods

  • onCreate()  

โดยส่วนมากจะทำการเริ่มต้นส่วนประกอบของ fragment
ที่ต้องการผูกขาดแม้ว่า fragment จะอยู่ในเสตรท : paused , stoped หรือ resumed.

  • onCreateView()  
เราควร return view จาก metod นี้ และสามารถ return null ถ้า fragment ไม่ได้ provide UI.
และมีพารามิเตอร์ชื่อ savedInstanceState คือ Bundle ที่เก็บ previous instance ของ fragment

  • onPause()
คุณควรจะ commit การเปลี่ยนแปลงใดใดที่เกินจาก current user session
เพราะ User อาจจะไม่กลับเข้ามา


" Most applications should implement at least these three methods for every fragment "
แต่มีอีกหลาย callbak methods ที่ควรจะนำมาใช้จัดการขั้นตอนต่างๆของ fragment
ดูได้ในนี้ครับ http://developer.android.com/guide/components/fragments.html#Lifecycle

ปล.การ retain state ของ fragment หลังจากที่ process killed แล้ว
สามารถทำได้ทั้งใน onCreate(), onCreateView() หรือ onActivityCreate()






Adding a fragment to an activity

มี 2 วิธีในการ add fragment ไปยัง activity layout

วิธีแรก : ประกาศ fragment ภายใน layout file ของ activity

<fragment android:name="com.example.news.ArticleListFragment"
    android:id="@+id/list"
    android:layout_weight="1"
    android:layout_width="0dp"
    android:layout_height="match_parent" />


วิธีที่สอง : programmatically add the fragment to an existing ViewGroup.
ถ้าจะสร้างจากในไฟล์ java code ก็ต้องเรียก Instance ของ fragment transactions ก่อน
เพื่อเตรียมพร้อมที่จะ add fragment


FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();


ระบุ fragment ที่จะ add , view ที่จะ insert เข้าไป


ExamFragment ExamFragment = new ExamFragment();
fragmentTransaction.add(android.R.id.content, ExamFragment, "tag");
fragmentTransaction.commit();




Adding a fragment without a UI

ใช้ add(Fragment, Tag) เพื่อสร้าง background behavior สำหรับ Activity
โดยไม่จำเป็นต้องมี onCreate() เพราะวิธีนี้จะไม่มี fragment ใน activity layout
หลังจากนี้จะเรียกใช้ Fragment โดยการ :  findFragmentByTag()





Methods ที่ใช้บ่อยๆของ FragmentManager

  • beginTransaction();
  • findFragmentById()  หรือ  findFragmentByTag()
  • pop fragments ออกจาก back stack โดยการใช้ popBackStack()
  • listener changes to back stack โดยการใช้ addOnBackStackChangedListener()
http://developer.android.com/reference/android/app/FragmentManager.html





Performing Fragment Transactions

ถือเป็น Great feature ของ fragments ที่สามารถ add, remove , replace ,
และการดำเนินการอื่นๆในการตอบสนองกับผู้ใช้

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();


แต่ละ Transaction คือ set ที่ต้องการเปลี่ยน
แต่ละ set ของข้อมูลที่ถูก commit เราเรียกว่า transaction

และเราสามารถสั่งการโดยใช้ FragmentTransaction , และก่อนที่จะ commit
อาจจะ addToBackStack , โดย back stack นี้จะถูกจัดการโดย activity
และยอมรับให้ผู้ใช้ return previous fragment state, โดยกดปุ่ม "back"
(หรืออาจจะทำเป็นปุ่มสั่ง getActivity().getFragmentManager().popBackStack();  เพื่อปิดหน้านั้น )



ตามโค้ดด้านบน newFragment จะ replaces ทุกอย่าง(currently)
ใน layout container นี่จะหมายถึงไอดีที่เราระบุว่า  R.id.fragment_container
หรือจะ add หลายๆครั้งไปยัง transaction ก็ย่อมได้
แล้วให้ลองกด Back ดูก็จะ reverse them all together เช่นกัน.

Tip : สำหรับการเปลี่ยนแปลงแต่ละ transition สามารถใส่ animation
โดยการใช้ setTransition() ก่อนจะ commit ประมาณนี้


FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_content, newFragment);
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);    <<  SetTransition
transaction.commit();


ปัญหาที่อาจเกิดขึ้น : ควร commit ก่อนที่จะมีการ saving to state   ถ้าผู้ใช้ออกจาก Activity
แล้วคุณพยาม commit หลังจากจุดนี้ก็จะเกิด Exeception ขึ้น, 
หลังจากการคอมมิท state จะหายไป ถ้า activity ต้องการ restored 
แต่แก้ปัญหาได้ด้วย commitAllowingStateLoss()






Communicating with the Activity

fragment สามารถ access Activity ได้ด้วยการใช้ getActivity()
ตัวอย่างง่ายๆเช่นการเปลี่ยน Text ของ Button ที่อยู่ใน activity layout

Button button = (Button) getActivity().findViewById(R.id.btn_changetxt);
button.setText("ok");


*แนะนำให้ทำใน onActivityCreated() หรือ onResume()

img src : https://www.youtube.com/watch?v=Cmx6bYlMhXo



img src : https://www.youtube.com/watch?v=Cmx6bYlMhXo




Activity สามารถ call methods ใน fragment โดยการอ้างอิงไปยัง Fragment
จาก FragmentManager ตามตัวอย่างด้านล่างนี้ครับ

Fragment myfragment = getFragmentManager().findFragmentById(R.id.simple_fragment_layout);
TextView txt_topic = (TextView)myfragment.getView().findViewById(R.id.textview_in_fragment);
txt_topic.setText("Edit TextView by HostActivity");



Creating event callbacks to the activity

ในบางเคสคุณอาจต้องการให้ fragment share events กับ Activity.
ทางเลือกที่ดีที่สุดคือระบุ callback interface ใน fragment
และต้องการให้ host activity implement มันด้วยเช่นกัน

เมื่อ activity ได้รับ callback ผ่าน interface,
มันสามารถ share ข้อมูลกับ fragment อื่นๆ ใน layout ตามความจำเป็น


สำหรับตัวอย่าง, ถ้า Application มี 2 fragment ใน activity เหมือนด้านบนที่เคยกล่าวมา
(Fragment : A = list, B = content)

fragment A ต้อง tell activity เมื่อผู้ใช้ selected list item ดังนั้นที่สามารถติดต่อ fragment B เพื่อแสดง article. ในเคสนี้  OnArticleSelectedListener interface จะถูกประกาศใน Fragment A



Activity ที่ทำการ implements OnArticleSelectedListener interface และ overrides onArticleSelected()  นี้ก็เพื่อแจ้งเตือนเหตุการณ์จาก Fragment A ไปยัง Fragment B

เพื่อมั่นใจว่า host activity implement interface,  Fragment A
จะมี onAttach()  callback method (ที่ system จะ calls เมื่อ add fragment ไปยัง activity)



ยกตัวอย่าง OnArticleSelectedListener โดยการ Casting Activity ที่ถูกส่งเข้าไปใน onAttach();


ตามโค้ดด้านบน

...ถ้าสำเร็จ mListener member จะเก็บ references ที่ชี้ไปยัง activity ที่ implement OnArticleSelectedListener interface  (โดยปกติจะเป็น OnFragmentInteractionListener)

ถ้า host activity ยังไม่ได้ implemented interface,  fragment จะ throws ClassCastException.
ดังนั้นที่ fragment สามารถ share events กับ activity  โดยการใช้ calling methods ที่กำหนดโดย OnArticleSelectedListener

Example
ถ้า fragment A สืบทอดจาก LisFragment
แต่ละครั้งที่ผู้ใช้คลิก list item, System จะ Call : onListItemClick() ใน Fragment,


ซึ่งก็เรียก onArticleSelected() เพื่อที่จะ share event กับ Activity


parameter : id ที่เห็นในภาพคือ row id ที่ผู้ใช้คลิก,
ซึ่ง activity (or other fragment) ใช้เพื่อ fetch article จาก application ContentProvider


Example Code in fragment











Handling the Fragment Lifecycle



Fragment สามารถมีได้ 3 state ดังนี้

Resumed
คือสถานะที่ Fragment สามารถมองเห็นได้ปกติใน activity ที่กำลังรัน

Paused
มี Activity อื่นเข้ามาใน Foreground ทำให้ Activity บางส่วนถูกบดบัง
แต่ยังไม่ครอบคลุมทั้งหน้าจอ (fragment ยังสามารถมองเห็นได้)

Stopped
เมื่อ fragment ไม่สามารถมองเห็นได้
รวมถึงเคสที่ fragment มีการ removed จาก activity แต่เพิ่มไปยัง back stack.
fragment จะยังคงมีชีวิตอยู่เพราะระบบจะทำการเก็บ State และ Member information
และเมื่อ fragment ไม่สามารถมองเห็นได้จะถูก Kill พร้อม activity

ข้อควรระวัง : ถ้าคุณต้องการ Context object ใน Fragment, สามารถใช้ getActivity แทน
แต่ Fragment ต้อง attached ไปยัง activity ซะก่อนไม่งั้น getActivity จะ return null




นอกจากนี้ Activity, ยังสามารถ(retain)
เก็บรักษา State ของ fragment 

โดยใช้ Bundle,
ในเคสที่ activity ถูก kill และคุณต้องการ restore fragment state เมื่อ activity recreate.

คุณสามารถ save state ใน onSaveInstanceState() , onDestroyView และ restore มันระหว่าง
onCreate() หรือ onCreateView() หรือ onActivityCreated() ตามสถานการณ์

( For more information about saving state, see the Activities document. )
http://developer.android.com/guide/components/activities.html#SavingActivityState




There are also a few subclasses 
that you might want to extend, 
instead of the base Fragment class:

  • DialogFragment
  • ListFragment
  • PreferenceFragment


ref : http://developer.android.com/reference/android/app/Fragment.html


ไม่มีความคิดเห็น:

แสดงความคิดเห็น