สรุป 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()
และมีพารามิเตอร์ชื่อ savedInstanceState คือ Bundle ที่เก็บ previous instance ของ fragment
- onPause()
เพราะ 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" />
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
เพื่อเตรียมพร้อมที่จะ 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()
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:
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
ไม่มีความคิดเห็น:
แสดงความคิดเห็น