安卓APP_ Fragment(3)—— Fragment的生命周期
摘自:安卓APP_ Fragment(3)—— Fragment的生命周期
作者:丶PURSUING
發布時間: 2021-04-16 22:32:12
網址:https://blog.csdn.net/weixin_44742824/article/details/115768202
目錄
- Fragment生命周期函數一覽
- 編程感受Fragment生命周期
- 演示所用的代碼
- 各個事件對應的生命周期函數調用情況
- (1)打開界面:觸發生命周期
- (2)點擊home鍵,返回桌面
- (3)重新打開fragment界面
- (4)返回按鍵,返回到桌面
- 前4種情況小結:
- 重點理解:棧管理下生命周期函數調用情況
- (1)打開界面,即創建過程與上面一樣
- (2)替換fragment
- (3)按下返回后,BlankFragment1出棧
- (4)BlankFragment2下返回桌面與重回界面
- (5)關閉應用,即刪除了Activity
- Fragment生命周期注意事項再強調
Fragment生命周期函數一覽
Activity和Fragment的生命周期非常類似,Fragment要更加細分一些,如下圖:
由上圖可知,所有的生命周期函數必須在 綁定(onAttach) 與 解綁(onDetach) 兩者之間執行。
Fragment的生命周期非常重要,在項目中Fragment生命周期的濫用,會導致后臺收集到很多的異常,而異常的根本原因是對其生命周期沒有按照規則執行,例如:在fragment中從Activity獲取的變量為null。
編程感受Fragment生命周期
生命周期難點所在:生命周期的調度原則。
這些生命周期函數并不是每次fragment變化的時候都會全部調用,而是只會調用其中某幾個,這就需要我們知道在各種情況下的調用情況。
根據調用情況,我們才清除解析bandle,解析xml,UI復位,清零等等應該放在哪個生命周期函數中。
后面例子中有體現:
onCreate()要對從activity傳過來的bundle進行解析等
onCreateView()要解析xml,設置button等
演示所用的代碼
代碼結構一覽:
MainActivity.java
在這里創建了兩個按鈕的點擊事件,點擊后創建或者切換不同的fragment。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button1 = findViewById(R.id.btn_1);button1.setOnClickListener(this);Button button2 = findViewById(R.id.btn_2);button2.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_1:Bundle bundle = new Bundle();//將Activity中的信息放進bundlebundle.putString("message", "my name is zhua");//需要實例化一個BlankFragment1對象bfBlankFragment1 bf = new BlankFragment1();//數據傳入bf中bf.setArguments(bundle);//動態切換fragmentreplaceFragment(bf);break;case R.id.btn_2:replaceFragment(new BlankFragment2());break;}}//啟動fragment生命周期private void replaceFragment(Fragment fragment) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.fm, fragment);transaction.addToBackStack(null);transaction.commit();} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
activity_main.xml
重點看FrameLayout布局,本例所用的兩個fragment切換顯示就在這個布局上。
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn_1"android:text="change_1"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn_2"android:text="change_2"/><!-- 除去按鈕,剩余的空間都是FrameLayout--><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/fm"android:background="@color/teal_200"/></LinearLayout>- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
BlankFragment1.java
這是本篇章的重點,把所有的fragment生命周期函數按照 一、Fragment生命周期函數一覽 圖片順序編寫。在每個生命周期函數中,都打印有調試信息,方便追蹤在不同的執行狀況下各個函數的調用情況。
public class BlankFragment1 extends Fragment {private String TAG = "zhua";//因為onCreateView函數可能會被調用多次,為了防止被解析多次而浪費資源,rootview要定義為全局private View rootview;@Overridepublic void onAttach(@NonNull Context context) {super.onAttach(context);Log.e(TAG, "onAttach: ");}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//這個getArguments返回的是在MainActivity中傳入的bundleBundle bundle = this.getArguments();//獲取bundle里面保存的內容String string = bundle.getString("message");//在fragment中打印從Activity中傳遞來的信息Log.e(TAG, "onCreate: " );}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {Log.e(TAG, "onCreateView: ");//必須先進行判斷,如果沒有解析過再進行解析,防止被多次調用if(rootview == null){// 用inflater解析器進行xml解析 要渲染的布局 xml副本,直接containerrootview = inflater.inflate(R.layout.fragment_blank1,container,false);}/*onCreateView中可以對Button進行綁定(如果需要使用Button)Button button1 = rootview.findViewById(R.id.btn_1);button1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});*/return rootview;}@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);Log.e(TAG, "onActivityCreated: " );}@Overridepublic void onStart() {super.onStart();Log.e(TAG, "onStart: " );}@Overridepublic void onResume() {super.onResume();Log.e(TAG, "onResume: " );}@Overridepublic void onPause() {super.onPause();Log.e(TAG, "onPause: " );}@Overridepublic void onStop() {super.onStop();Log.e(TAG, "onStop: " );}@Overridepublic void onDestroyView() {super.onDestroyView();Log.e(TAG, "onDestroyView: " );}@Overridepublic void onDestroy() {super.onDestroy();Log.e(TAG, "onDestroy: " );}@Overridepublic void onDetach() {super.onDetach();Log.e(TAG, "onDetach: " );} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
BlankFragment2.java
public class BlankFragment2 extends Fragment {private View rootview;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {//必須先進行判斷,如果沒有解析過再進行解析,防止被多次調用if(rootview == null){// 用inflater解析器進行xml解析 要渲染的布局 xml副本,直接containerrootview = inflater.inflate(R.layout.fragment_blank1,container,false);}return rootview;} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
fragment_blank1.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".BlankFragment1"><!-- TODO: Update blank fragment layout --><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:background="#ffff00"android:textSize="40dp"android:text="@string/hello_blank_fragment" /></FrameLayout>- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
fragment_blank2.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".BlankFragment2"><!-- TODO: Update blank fragment layout --><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:text="@string/hello_blank_fragment" /></FrameLayout>- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
各個事件對應的生命周期函數調用情況
(1)打開界面:觸發生命周期
點擊按鈕,創建fragment,調用了如下六個函數:
即為
(2)點擊home鍵,返回桌面
可以看到調用的是暫停和停止
如果要將UI進行復位,進行狀態清0,那么就要放在onPause里面進行
(3)重新打開fragment界面
調用了開始與重啟
(4)返回按鍵,返回到桌面
因為這個返回已經導致了Activity生命周期的結束,所以fragment暫停 > 停止 > 銷毀布局 > 銷毀fragment > 解除綁定
前4種情況小結:
生命周期的創建與銷毀過程:是完全逆向的,一 一對應的過程。
重點理解:棧管理下生命周期函數調用情況
如果fragment是放進棧里面管理(相當于添加了一個保險箱),而不是直接銷毀,那fragment生命周期又會有什么不同呢?
(1)打開界面,即創建過程與上面一樣
點擊的是CHANGE_1,此時界面是BlankFragment1
(2)替換fragment
點擊第二個按鈕切換fragment,此時界面是BlankFragment12
當替換的時候,就需要銷毀view(onDestroyView,注意哦是刪除了布局,而不是fragment),因為當前所展示的Activity里面的fragement已經變了。
(3)按下返回后,BlankFragment1出棧
按一下返回,切換回來,此時界面是BlankFragment1
可以發現(2)(3)非常像是逆著過來的過程。
(4)BlankFragment2下返回桌面與重回界面
在界面為BlankFragment2(即下圖界面)執行1 2 3 操作
注意,打印信息僅僅在BlankFragment1中有設置
(5)關閉應用,即刪除了Activity
可以看到fragment生命周期完全結束,銷毀fragment并解綁。
Fragment生命周期注意事項再強調
(1)將來開發者會圍繞fragment生命周期花費很多時間來解決問題,比如fragement切換白屏,顯示異常等。
(2)fragement的使用一定是需要在生命周期函數onAttach與onDetach之間。
(3)fragement的使用一定要嚴格遵守生命周期的規則,在正確的地方寫恰當的代碼。
總結
以上是生活随笔為你收集整理的安卓APP_ Fragment(3)—— Fragment的生命周期的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从内存中加载DLL Delphi版(转)
- 下一篇: 算法图解-----十种常用算法