1,简介
Fragement(碎片)允许将Activity拆分成多个完全独立封装的可重用组件,每个组件有它自己的生命周期和UI布局,由此可见,Fragement依赖于Activity,它的生命周期直接被其所属的宿主activity的生命周期影响。
形象的理解Fragement,手机屏幕如下图所示:
Fragement 具有以下优点:
- 组件重用,多个Activity可重用同一个Fragement;
- 为不同屏幕大小的设备创建动态的灵活的UI,在Activity运行过程中,可以添加、移除或者替换Fragment(add()、remove()、replace())
2,生命周期
Fragement的生命周期镜像它的宿主Activity的生命周期事件。若Activity进入active-resumed状态的时候,添加或者移除一个Fragement就会影响它自己的生命周期。
Fragement生命周期方面如下:
/** * Listing 4-4: Fragment skeleton code * Listing 4-5: Fragment lifecycle event handlers */ package com.paad.fragments; import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class MySkeletonFragment extends Fragment { // Called when the Fragment is attached to its parent Activity. @Override public void onAttach(Activity activity) { super.onAttach(activity); // Get a reference to the parent Activity. } // Called to do the initial creation of the Fragment. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Initialize the Fragment. } // Called once the Fragment has been created in order for it to // create its user interface. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Create, or inflate the Fragment's UI, and return it. // If this Fragment has no UI then return null. return inflater.inflate(R.layout.my_fragment, container, false); } // Called once the parent Activity and the Fragment's UI have // been created. @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Complete the Fragment initialization �particularly anything // that requires the parent Activity to be initialized or the // Fragment's view to be fully inflated. } // Called at the start of the visible lifetime. @Override public void onStart(){ super.onStart(); // Apply any required UI change now that the Fragment is visible. } // Called at the start of the active lifetime. @Override public void onResume(){ super.onResume(); // Resume any paused UI updates, threads, or processes required // by the Fragment but suspended when it became inactive. } // Called at the end of the active lifetime. @Override public void onPause(){ // Suspend UI updates, threads, or CPU intensive processes // that don't need to be updated when the Activity isn't // the active foreground activity. // Persist all edits or state changes // as after this call the process is likely to be killed. super.onPause(); } // Called to save UI state changes at the // end of the active lifecycle. @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save UI state changes to the savedInstanceState. // This bundle will be passed to onCreate, onCreateView, and // onCreateView if the parent Activity is killed and restarted. super.onSaveInstanceState(savedInstanceState); } // Called at the end of the visible lifetime. @Override public void onStop(){ // Suspend remaining UI updates, threads, or processing // that aren't required when the Fragment isn't visible. super.onStop(); } // Called when the Fragment's View has been detached. @Override public void onDestroyView() { // Clean up resources related to the View. super.onDestroyView(); } // Called at the end of the full lifetime. @Override public void onDestroy(){ // Clean up any resources including ending threads, // closing database connections etc. super.onDestroy(); } // Called when the Fragment has been detached from its parent Activity. @Override public void onDetach() { super.onDetach(); } }
生命周期要点:
- 开始于绑定到它的你Activity,结束于从父Activity分离,对应于onAttach 和onDetach事件,通常情况下,onAttach用来获取一下Fragement的父Activity的引用,为进一步初始化做准备;
- 不能依赖调用onDestroy方法来销毁它,因为此方面不定会被执行;
- 与Activity一样,应该使用onCreate方法来初始化Fragement,在其生命周期内创建的作用域对象,且确保只创建一次;
- 在onCreateView和onDestroyView上初始化和销毁UI;
- 当Fragement暂停或停止时,保存所有的UI状态和持久化所有的数据。
3,使用Fragement
最佳实践是使用容器View来创建布局,将Fragement在运行时放入容器内
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/ui_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" > </FrameLayout> <FrameLayout android:id="@+id/details_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="3"android:visibility =”gone” --隐藏 /> </LinearLayout>
在运行时使用Fragement transaction来动态填充布局,从而当配置改变时,能确保一致性,框架代码如下:
package com.paad.fragments; import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; public class MyFragmentActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Inflate the layout containing the Fragment containers setContentView(R.layout.fragment_container_layout); FragmentManager fm = getFragmentManager(); // Check to see if the Fragment back stack has been populated // If not, create and populate the layout. DetailsFragment detailsFragment = (DetailsFragment)fm.findFragmentById(R.id.details_container); if (detailsFragment == null) { FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.details_container, new DetailsFragment()); ft.add(R.id.ui_container, new MyListFragment()); ft.commit(); } } }
package com.paad.weatherstation; import com.paad.fragments.R; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class DetailsFragment extends Fragment { public DetailsFragment() { } // Called once the Fragment has been created in order for it to // create its user interface. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Create, or inflate the Fragment's UI, and return it. // If this Fragment has no UI then return null. return inflater.inflate(R.layout.details_fragment, container, false); } }
package com.paad.weatherstation; import com.paad.fragments.R; import android.annotation.SuppressLint; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class MyListFragment extends Fragment { public MyListFragment() { } // Called once the Fragment has been created in order for it to // create its user interface. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Create, or inflate the Fragment's UI, and return it. // If this Fragment has no UI then return null. return inflater.inflate(R.layout.list_fragment, container, false); } }
Fragement 和Activity之间的接口:
- 任何Fragement中可使用getActivity方法返回对父Activity的引用;
- 在fragement需要和它的主Activity共享事件的地方,最好在Fragement中创建回调接口,而主Activity必须实现它来监听Fragement中的改变;
package com.paad.fragments; import android.app.Activity; import android.app.Fragment; /** * MOVED TO PA4AD_Ch04_Seasons */ public class SeasonFragment extends Fragment { public interface OnSeasonSelectedListener { public void onSeasonSelected(Season season); } private OnSeasonSelectedListener onSeasonSelectedListener; private Season currentSeason; @Override public void onAttach(Activity activity) { super.onAttach(activity); try { onSeasonSelectedListener = (OnSeasonSelectedListener)activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnSeasonSelectedListener"); } } private void setSeason(Season season) { currentSeason = season; onSeasonSelectedListener.onSeasonSelected(season); } }
若理解有难道,可以了解一下JAVA编程思想中的上塑造型,内部类,接口方面的知识