onInflate()和onAttach()
Fragment可有一個view hierarchy,以之與用戶互動。這個view層級可以根據XML布局文件被創建(inflated)或通過代碼創建。view層級需要與activity關聯,才能被用戶看見。Fragment的最初的兩個生命周期為onInflate和onAttach。
/* 左邊fragment是list,和ListActivity一樣,繼承ListFragment */
public class TitleFragment extends ListFragment{
private FragmentBasicTest myActivity = null;
private int mCurCheckPosition = 0;
…... 略 ……
@Override //【2】在fragment與activity關聯后調用onAttach()。由於右邊fragment的具體實現在activity的showDetails()中實現,需要獲取activity的對象。 當然也可以直接用getActivity()獲取。
public void onAttach(Activity activity) {
showInfo("onAttach() is called. activity is " + activity);
showInfo(" getActivity() : " + getActivity());
super.onAttach(activity);
myActivity = (FragmentBasicTest)activity;
}
@Override//【1】首先調用:在Activity調用setContentView()時,xml中有<fragment>時被調用。bundle存貯的是fragment的狀態,並非初始化的值。一般而言,此時太早,還沒有和activity關聯,一般很少需要在此進行處理,除非我們需要處理fragment的屬性或參數。在API的reference中,Fragment的主要lifecycle甚至沒有將onInflate()列入,因此在實際編程中,會較少用到。
public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
showInfo("onInfalte() is called");
showInfo(" activity : " + activity);
showInfo(" getActivity() : " + getActivity()); //Fragment尚為關聯activity
showInfo(" attribute是fragment的屬相,例如R.id.titles = " + R.id.titles);
for(int i = 0 ; i< attrs.getAttributeCount() ; i ++){
showInfo(" attribute " + i + " :" + attrs.getAttributeName(i) + " = " + attrs.getAttributeValue(i));
}
showInfo(" bundle : " + savedInstanceState);
super.onInflate(activity, attrs, savedInstanceState);
}
private void showInfo(String s){
Log.d("TitleFragment",s);
}
}
我們看看運行的logcat顯示。我們可以看出,在activity調用setContentView時,先調用Flagment中的onflate(),然后調用onAttach()。在onInfalte()中可以讀取到我們在xml文件中<fragment… >設置的屬性。在后面實現右邊的fragment中,由於布局文件中<fragment …>中並沒有指定class屬性,而是在代碼中實現,故沒有onInflate()狀態。
與activity的關聯:看到onInfalte()和onAttach()都可以獲得activity對象,但是如果采用getActivity()來獲取,則發現onInfalte()的階段對處理UI太早,都不能關聯到activity。
參數:在整個生命周期,可以通過getArguments()來獲取參數,但是不能在與activity關聯后進行setArgments(),只能在初始化極早的階段,例如構造函數和onInflate()。
onCreate()和onCreateView()
@Override //【3】在創建fragment中進行初始化時調用。注意此處的bundle參數,是存儲fragment的狀態。如果我們要為fragment啟動一個后台線程,可以考慮將代碼放於此處。
public void onCreate(Bundle savedInstanceState) {
showInfo("onCreate() is called. ");
super.onCreate(savedInstanceState);
}
@Override //【4】創建fragment,並返回fragment的view層次結構,用於對UI的設計。本例繼承了ListFragment實現,由其生成ListView,它的資源ID是android.R.id.list1,或者可以通過getListView()來獲取。我們在此不需要在進行特別的處理,僅用於跟蹤生命周期。
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
showInfo("onCreateView() is called. ");
return super.onCreateView(inflater, container, savedInstanceState);
}
onCreate()和onCreateView()都是在activity調用setContentView()時被調用。也就是activity上未完成onCreate(),因此不應該在此加入與activity的view相關的代碼。而后面的生命周期這是在activity完成onCreate()之后調用的。
onActivityCreated()
onActivityCreated顧名思義,是在activity完成onCreate()后被調用。我們可以在此處理activity的其他UI操作,而其他的fragment已經與activity關聯,我們可以進行相互間處理。這也是用戶看到UI界面之前的最后一個狀態,對於從saved狀態中重新創建activity及fragment來講是重要狀態。
回想一下,在ListActivity中是在setContentView()后面進行Adapter的設置,因為setContentView已經提供了view層級,因此在fragment中具體設置list也放在fragment的onCreateView()之后的生命周期onActivityCreated()中執行。
@Override //【5】onActivityCreated()在activity完成onCreate()后執行,在此可以加入UI設計(onCreateView())之后,UI被用戶看到之前的代碼。
public void onActivityCreated(Bundle savedInstanceState) {
showInfo("onActivityCreated() is called.");
super.onActivityCreated(savedInstanceState);
// 1)通過Adapter進行view和data的關聯
setListAdapter(new ArrayAdapter<String>(getActivity(), //注意:在ListFragment中不要直接和ListView(通過id或者getListView()獲取)關聯,而要用setListAdapter()
android.R.layout.simple_list_item_1,
BooksInfo.TITLES));
ListView lv = getListView();
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
lv.setSelection(mCurCheckPosition);
//2)根據書名設置右邊framgent UI。
myActivity.showDetails(mCurCheckPosition);
}
onStart()、onResume()、onPause()和onStop()
這幾個狀態和activty的相應狀體相似,對應為可視,可互動,不可互動和不可視。和activity的生命周期圖相對比,從不可視的后台回復到可視的前台的過程是onStop()—>onRestart()—>onStart()。而fragment為onStop()—>onStart()。
onDestroyView()、onDestroy和onDetach()
當fragment允許與view相關的資源釋放時調用onDestroyView(),清空通過onCreateView()所返回的view。接着,onDestroy()進行最后fragment狀態的清空。最后調用onDetach(),刪除與activity的關聯()。
與用戶互動處理
@Override //當用戶點擊書名,在右邊fragment中顯示相關的內容。在ListFragment中可以直接通過回調函數onListItemClick來實現。
public void onListItemClick(ListView l, View v, int position, long id) {
mCurCheckPosition = position;
myActivity.showDetails(mCurCheckPosition);
}
本博文涉及的例子代碼,可以在Pro Android學習:Fragment中下載。