本文主要介紹下Android Fragment的生命周期绞铃,相關(guān)的API以及和Activity通信的簡單實踐
一哎垦、生命周期:
Fragment創(chuàng)建銷毀時,fragment和所依賴的activity生命周期的執(zhí)行順序恃疯,注意看log的TAG
1.創(chuàng)建時
01-12 17:57:24.823 28028-28028/? I/ActivityLife: onCreate...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onAttach...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onCreate...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onCreateView...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onActivityCreated...
01-12 17:57:24.843 28028-28028/? I/ActivityLife: onStart...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onStart...
01-12 17:57:24.843 28028-28028/? I/ActivityLife: onResume...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onResume...
2.銷毀時
01-12 17:57:40.583 28028-28028/? I/FragmentLife: onPause...
01-12 17:57:40.583 28028-28028/? I/ActivityLife: onPause...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onStop...
01-12 17:57:40.883 28028-28028/? I/ActivityLife: onStop...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onDestroyView...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onDestroy...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onDetach...
01-12 17:57:40.883 28028-28028/? I/ActivityLife: onDestroy...
二漏设、Activity中,F(xiàn)ragment的2種加載方法
1.靜態(tài)加載
(1)創(chuàng)建Fragment類和布局文件(fragment1.xml)
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ff00" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is fragment 1"
android:textColor="#000000"
android:textSize="25sp" />
</LinearLayout>
(2)在activity布局文件(activity_main.xml)中添加fragment布局
...
<fragment
android:id="@+id/fragment1"
android:name="com.example.sven.fragementdemo.Fragment1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
...
2.動態(tài)加載
(1) 在activity布局文件中添加FragmentLayout節(jié)點
...
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
...
(2) java代碼中動態(tài)加載
...
1.獲取fragmentManager
FragmentManager fragmentManager = getFragmentManager();
2.獲取FragmentTransaction
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
3.創(chuàng)建需要的Fragment
Fragment fragment = new Fragment1();
4.動態(tài)添加fragment
將創(chuàng)建的fragment添加到Activity布局文件中定義的占位符中(FrameLayout)
fragmentTransaction.add(R.id.fragment_container,fragment).commit();
...
三今妄、FragmentTransaction方法解析結(jié)合Fragment的生命周期
對Fragment的操作主要是通過調(diào)用FragmentTransaction類的方法進(jìn)行的郑口,F(xiàn)ragmentTransaction的對象通常是通過getFragmentManager().beginTransaction()獲取的
1.add & remove / replace
(1) add 往Activity中添加一個Fragment,對應(yīng)的fragment的生命周期如下:
06-13 12:01:43.406 1986-1986/? I/Fragment3: onAttach
06-13 12:01:43.406 1986-1986/? I/Fragment3: onCreate
06-13 12:01:43.406 1986-1986/? I/Fragment3: onCreateView
06-13 12:01:43.406 1986-1986/? I/Fragment3: onActivityCreated
06-13 12:01:43.406 1986-1986/? I/Fragment3: onStart
06-13 12:01:43.406 1986-1986/? I/Fragment3: onResume
(2) remove 從Activity中移除一個Fragment盾鳞,和add配對使用犬性,通常是直接用replace
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onPause
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onStop
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onDestroyView
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onDestroy
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onDetach
(3) replace 使用另一個fragment替換當(dāng)前的,先remove掉當(dāng)前的再add新的腾仅,參考add和remove的過程
2.attach & detach
(1) attach 重建view視圖乒裆,添加到UI上并顯示,和detach配合使用推励,顯示一個被detach的fragment
06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onCreateView
06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onActivityCreated
06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onStart
06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onResume
(2) detach 會將view從UI中移除,和remove()不同,此時fragment的狀態(tài)依然由FragmentManager維護(hù)鹤耍,fragment的實例還存在,但是視圖被銷毀了
06-13 11:58:13.486 29992-29992/com.example.sven.fragementdemo I/Fragment3: onPause
06-13 11:58:13.486 29992-29992/com.example.sven.fragementdemo I/Fragment3: onStop
06-13 11:58:13.486 29992-29992/com.example.sven.fragementdemo I/Fragment3: onDestroyView
3.hide & show
不涉及fragment生命周期验辞,調(diào)試過程中沒有看到想象中onPause稿黄、onStop、onResume函數(shù)的調(diào)用過程跌造,hide時fragment的視圖和實例都不會被銷毀杆怕,只是視圖可見與不可見的變化。賬號登陸界面應(yīng)該用的比較多壳贪,能夠保存用戶的輸入陵珍,和detach區(qū)別就是detach不能夠的保存界面的信息(例如EditText的輸入),每次detach撑碴,attch時界面都會重繪
4.commit
提交對fragment的一系列操作撑教。注意每一次對fragment的操作都要開一次事務(wù),commit一次醉拓。commit和FragmentManager.beginTransaction()要配對使用伟姐。(很像數(shù)據(jù)庫收苏,暫時沒深入研究)
5.addToBackStack(String)
把當(dāng)前事務(wù)的變化情況添加到回退棧,下節(jié)詳細(xì)講下
tips:
1.以上這些方法通常是在Activity中使用,依附于同一個Activity的多個fragment的各種切換
2.fragment真正的實例其實是要通過FragmentTransaction.add愤兵,只有在add時才會執(zhí)行onCreate鹿霸,new的時候拿到只是一個引用 并沒有執(zhí)行生命周期函數(shù)
3.使用attach/detach 或者 hide/show 都需要new出對象,并且執(zhí)行add
4.add/remove/replace/hide/show后都要commit其效果才會在屏幕上顯示出來
四秆乳、Fragment的回退棧
Fragment的會退棧是用來保存每一次Fragment事務(wù)發(fā)生的變化懦鼠,如果你將Fragment任務(wù)添加到回退棧,當(dāng)點擊back鍵時屹堰,將看到上一次的保存的Fragment肛冶,一旦Fragment完全從后退棧中彈出,用戶再次點擊后退鍵扯键,則退出當(dāng)前Activity睦袖,如果被移除的Fragment沒有添加到回退棧,例如執(zhí)行remove或者replace時荣刑,這個Fragment實例將會被銷毀
理解以下3種情況 在同一個Actity中馅笙,fragment1 跳轉(zhuǎn)到fragment2,然后按back退出時的不同情況
public void jump2fragment2(){
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragment之間跳轉(zhuǎn)時
1.只采用replace 實例會被銷毀 back鍵一次
fragmentTransaction.replace(R.id.fragment_container,new Fragment2());
fragmentTransaction.addToBackStack(null);
2.把當(dāng)前事務(wù)的變化情況添加到回退棧,視圖會被銷毀但是實例還在(back 2次)
fragmentTransaction.replace(R.id.fragment_container,new Fragment2());
fragmentTransaction.addToBackStack(null);
3.采用hide方式 實例不會被銷毀,視圖也不會被銷毀(back 2次)
fragmentTransaction.hide(this);
fragmentTransaction.add(R.id.fragment_container, new Fragment2());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
五厉亏、Fragment與Activity之間的通信
1.一般Fragment依附于Activity存在董习,因此與Activity之間的通信可以歸納為以下3點:
(1)Fragment中可以通過getActivity得到當(dāng)前綁定的Activity的實例,然后進(jìn)行操作
例如你在想在某個fragment中通過activity拿到fragment1的數(shù)據(jù)可以這樣做
public void getfragment1text() {
getActivity().findViewById(R.id.fragment1_text)
}
(2) 如果你Activity中包含自己管理的Fragment的引用爱只,可以通過引用直接訪問所有的Fragment的public方法
(3) 如果Activity中未保存任何Fragment的引用皿淋,那么沒關(guān)系,每個Fragment都有一個唯一的TAG或者ID,可以通過getFragmentManager.findFragmentByTag()或者findFragmentById()獲得任何Fragment實例虱颗,然后進(jìn)行操作 fragment的id其實是無法設(shè)置的沥匈,add或replace時設(shè)置的id是其實要插入fragment所在ViewGroup的id,tag可以在add或replace時設(shè)置忘渔。https://stackoverflow.com/questions/9363072/android-set-fragment-id
public class MainActivity extends AppCompatActivity {
private static final String TAG = "ActivityLife";
private Fragment1 fragment = new Fragment1();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
printLog("onCreate...");
setContentView(R.layout.activity_main);
// 1.獲取fragmentManager
FragmentManager fragmentManager = getFragmentManager();
// 2.獲取FragmentTransaction
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// 3.創(chuàng)建需要的Fragment
// Fragment fragment = new Fragment1();
// 4.動態(tài)添加fragment
// 將創(chuàng)建的fragment添加到Activity布局文件中定義的占位符中(FrameLayout)
fragmentTransaction.add(R.id.fragment_container, fragment, "fragment1").commit();
}
public void getFragmentMessage(View view){
//1.針對第2種情況
fragment.printSth();
//2.針對第3種情況
Fragment fragment = getFragmentManager().findFragmentByTag("fragment1");
printLog(fragment.toString());
fragment.onResume();
}
}
public class Fragment1 extends Fragment {
...
public void printSth() {
Log.i(TAG,"fragment3 printSth");
}
}
(4)更復(fù)雜的用法參考:
http://blog.csdn.net/lmj623565791/article/details/37992017
2.應(yīng)用場景主要就是通過Activity去管理多個Fragment的狀態(tài)
思路如下:
(1) 讓各個Fragment注冊一個監(jiān)聽接口高帖,讓Activity去implements這個監(jiān)聽接口
(2) 在Activity中new出各個Fragment的對象,獲取引用
(3) 將Fragment中的事件通過listener傳遞到Activity中畦粮,在Fragment中通過getActivity去調(diào)用監(jiān)聽方法
tips:
Fragment中的按鈕的事件響應(yīng)時不能通過在配置文件中加onClick屬性找到的散址,必須注冊onClickListenr(有2種方式)
原因參考:http://blog.csdn.net/Zafir6453/article/details/51383915
3.以上這些自己寫了個Demo,方便大家調(diào)試和學(xué)習(xí)
http://download.csdn.net/detail/time_traveller14/9870932
1.生命周期宣赔,回退棧预麸,參考fragment1,fragment2,MainActivity
2.FragmentTransaction及和Activity通信(fragment中不同的按鈕事件響應(yīng)) 參考fragment3,fragment4, Main2Activity
六.還未理解問題:
1.回退棧的使用場景,有了hide和detach為何還要加這個儒将,僅僅是為了多按一次back鍵吏祸?
2.hide和show為何沒有onPause和onResume的過程,hide為何不執(zhí)行onPause钩蚊,onStop呢贡翘?
3.remove 的真正含義銷毀還是出棧蹈矮,看許多資料解釋是銷毀掉,但為何remove掉鸣驱,commit完fragment!=null泛鸟,還能夠通過tag獲取到,但是去尋找fragment的視圖元素會報錯踊东?
4.屏幕旋轉(zhuǎn)時北滥,已經(jīng)判斷了onSavedInstance==null,為何還會繼續(xù)闸翅,log中 onCreate onCreateView會執(zhí)行再芋,要結(jié)合activity?
參考資料:
https://developer.android.com/guide/components/fragments.html
郭霖大神 http://blog.csdn.net/guolin_blog/article/details/8881711
鴻洋大神 http://blog.csdn.net/lmj623565791/article/details/37970961