Android Fragment的生命週期和返回棧
上一章節中(Android讓Fragment載入到Activity中),我們對Fragment的生命週期進行了簡單介紹,這一章節將對生命週期和返回棧進行詳細介紹。
一、Fragment的生命週期初探:
因為Fragment必須嵌入在Acitivity中使用,所以Fragment的生命週期和它所在的Activity是密切相關的。
如果Activity是暫停狀態,其中所有的Fragment都是暫停狀態;如果Activity是stopped狀態,這個Activity中所有的Fragment都不能被啟動;如果Activity被銷燬,那麼它其中的所有Fragment都會被銷燬。
但是,當Activity在活動狀態,可以獨立控制Fragment的狀態,比如加上或者移除Fragment。
當這樣進行fragment transaction(轉換)的時候,可以把fragment放入Activity的back stack中,這樣使用者就可以進行返回操作。
使用Fragment時,需要繼承Fragment或者Fragment的子類(DialogFragment, ListFragment, PreferenceFragment, WebViewFragment),所以Fragment的程式碼看起來和Activity的類似。
每當建立一個Fragment時,首先新增以下三個回撥方法:
- onCreate():系統在建立Fragment的時候呼叫這個方法,這裡應該初始化相關的元件,一些即便是被暫停或者被停止時依然需要保留的東西。
- onCreateView():當第一次繪製Fragment的UI時系統呼叫這個方法,該方法將返回一個View,如果Fragment不提供UI也可以返回null。注意,如果繼承自ListFragment,onCreateView()預設的實現會返回一個ListView,所以不用自己實現。
- onPause():當使用者離開Fragment時第一個呼叫這個方法,需要提交一些變化,因為使用者很可能不再返回來。
將Fragment載入到Activity當中有兩種方式:
- 方式一:新增Fragment到Activity的佈局檔案當中
- 方式二:在Activity的程式碼中動態新增Fragment(薦)
第一種方式雖然簡單但靈活性不夠。新增Fragment到Activity的佈局檔案當中,就等同於將Fragment及其檢視與activity的檢視繫結在一起,且在activity的生命週期過程中,無法切換fragment檢視。
第二種方式比較複雜,但也是唯一一種可以在執行時控制fragment的方式(載入、移除、替換)。
二、Fragment的生命週期詳解:
先來看一下官方文件的圖片吧:
我們再把Activity的生命週期和Fragment的生命週期對比一下,就清楚很多了:
我們還是在例項中來看一下Fragment的生命週期吧。
【例項】在MainActivity中載入一個Fragment:(完整版程式碼如下)
我們所建立的Fragment的佈局檔案fragment01.xml的程式碼如下:
<?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" > <RatingBar android:id="@+id/ratingBar1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" /> </LinearLayout>
MyFragment.java程式碼如下:(注意生命週期中每個方法的作用)
1 package com.example.m01_fragmentlifecycle; 2 3 import android.app.Activity; 4 import android.app.Fragment; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.LayoutInflater; 8 import android.view.View; 9 import android.view.ViewGroup; 10 11 public class MyFragment extends Fragment { 12 private final String TAG = "MyFragment"; 13 14 //獲得activity的傳遞的值 15 @Override 16 public void onAttach(Activity activity) { 17 // TODO Auto-generated method stub 18 super.onAttach(activity); 19 Log.i(TAG, "--MyFragment->>onAttach"); 20 } 21 22 //例項化成員變數 23 @Override 24 public void onCreate(Bundle savedInstanceState) { 25 // TODO Auto-generated method stub 26 super.onCreate(savedInstanceState); 27 Log.i(TAG, "--MyFragment->>onCreate"); 28 } 29 30 //給當前的fragment繪製UI佈局,可以使用執行緒更新UI 31 @Override 32 public View onCreateView(LayoutInflater inflater, ViewGroup container, 33 Bundle savedInstanceState) { 34 Log.i(TAG, "--MyFragment->>onCreateView"); 35 View view = inflater.inflate(R.layout.fragment01, null); 36 // TODO Auto-generated method stub 37 return view; 38 } 39 40 //表示activity執行oncreate方法完成了的時候會呼叫此方法 41 @Override 42 public void onActivityCreated(Bundle savedInstanceState) { 43 // TODO Auto-generated method stub 44 super.onActivityCreated(savedInstanceState); 45 Log.i(TAG, "--MyFragment->>onActivityCreated"); 46 } 47 48 //和activity一致 49 @Override 50 public void onStart() { 51 // TODO Auto-generated method stub 52 super.onStart(); 53 Log.i(TAG, "--MyFragment->>onStart"); 54 } 55 56 //和activity一致 57 @Override 58 public void onResume() { 59 // TODO Auto-generated method stub 60 super.onResume(); 61 Log.i(TAG, "--MyFragment->>onResume"); 62 } 63 64 //和activity一致 65 @Override 66 public void onPause() { 67 // TODO Auto-generated method stub 68 super.onPause(); 69 Log.i(TAG, "--MyFragment->>onPause"); 70 } 71 72 //和activity一致 73 @Override 74 public void onStop() { 75 // TODO Auto-generated method stub 76 super.onStop(); 77 Log.i(TAG, "--MyFragment->>onStop"); 78 } 79 80 //表示fragment銷燬相關聯的UI佈局 81 @Override 82 public void onDestroyView() { 83 // TODO Auto-generated method stub 84 super.onDestroyView(); 85 Log.i(TAG, "--MyFragment->>onDestroyView"); 86 } 87 88 //銷燬fragment物件 89 @Override 90 public void onDestroy() { 91 // TODO Auto-generated method stub 92 super.onDestroy(); 93 Log.i(TAG, "--MyFragment->>onDestroy"); 94 } 95 96 //脫離activity 97 @Override 98 public void onDetach() { 99 // TODO Auto-generated method stub 100 super.onDetach(); 101 Log.i(TAG, "--MyFragment->>onDetach"); 102 } 103 }
activity_main.xml的程式碼如下:
<LinearLayout 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" android:orientation="horizontal" tools:context=".MainActivity" > <LinearLayout android:id="@+id/line" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout> </LinearLayout>
MainActivity.java的程式碼如下:
1 package com.example.m01_fragmentlifecycle; 2 3 import android.os.Bundle; 4 import android.app.Activity; 5 import android.app.FragmentManager; 6 import android.app.FragmentTransaction; 7 import android.util.Log; 8 import android.view.Menu; 9 10 public class MainActivity extends Activity { 11 private final String TAG = "MainActivity"; 12 private FragmentManager manager; 13 private FragmentTransaction transaction; 14 15 @Override 16 protected void onCreate(Bundle savedInstanceState) { 17 super.onCreate(savedInstanceState); 18 setContentView(R.layout.activity_main); 19 manager = getFragmentManager(); 20 transaction = manager.beginTransaction(); 21 MyFragment fragment = new MyFragment(); 22 transaction.add(R.id.line, fragment); 23 transaction.commit(); 24 Log.i(TAG, "--MainActivity->>onCreate"); 25 } 26 27 @Override 28 protected void onStart() { 29 // TODO Auto-generated method stub 30 super.onStart(); 31 Log.i(TAG, "--MainActivity->>onStart"); 32 } 33 34 @Override 35 protected void onResume() { 36 // TODO Auto-generated method stub 37 super.onResume(); 38 Log.i(TAG, "--MainActivity->>onResume"); 39 } 40 41 @Override 42 protected void onPause() { 43 // TODO Auto-generated method stub 44 super.onPause(); 45 Log.i(TAG, "--MainActivity->>onPause"); 46 } 47 48 @Override 49 protected void onStop() { 50 // TODO Auto-generated method stub 51 super.onStop(); 52 Log.i(TAG, "--MainActivity->>onStop"); 53 } 54 55 @Override 56 protected void onRestart() { 57 // TODO Auto-generated method stub 58 super.onRestart(); 59 Log.i(TAG, "--MainActivity->>onRestart"); 60 } 61 @Override 62 protected void onDestroy() { 63 // TODO Auto-generated method stub 64 super.onDestroy(); 65 Log.i(TAG, "--MainActivity->>onDestroy"); 66 } 67 68 @Override 69 public boolean onCreateOptionsMenu(Menu menu) { 70 // Inflate the menu; this adds items to the action bar if it is present. 71 getMenuInflater().inflate(R.menu.main, menu); 72 return true; 73 } 74 }
可以看到,上面的程式碼在每個生命週期的方法裡都列印了日誌,然後我們來執行一下程式,可以看到列印日誌如下:
初次載入:(分成兩部分來看)
點選一下home鍵(或接入電話),列印日誌如下:
重新進入進入程式(或電話結束),列印日誌如下:
點選back鍵退出程式,列印日誌如下:
通過上面的日誌,我們能夠看出,Fragment和Activity的生命週期太相似了。只是有幾個Activity中沒有的新方法,需要重點介紹一下:
- onAttach方法:Fragment和Activity建立關聯的時候呼叫(獲得activity的傳遞的值)
- onCreateView方法:為Fragment建立檢視(載入佈局)時呼叫(給當前的fragment繪製UI佈局,可以使用執行緒更新UI)
- onActivityCreated方法:當Activity中的onCreate方法執行完後呼叫(表示activity執行oncreate方法完成了的時候會呼叫此方法)
- onDestroyView方法:Fragment中的佈局被移除時呼叫(表示fragment銷燬相關聯的UI佈局)
- onDetach方法:Fragment和Activity解除關聯的時候呼叫(脫離activity)
三、Fragment返回棧的管理:
將Fragment新增到返回棧中:
假設現在我們有兩個Fragment:Fragment01和Fragment02,我們現在從Fragment01的介面跳到Fragment02,然後按Back鍵,發現程式是直接退出了,而不是返回到Fragment01。如果現在想實現以下功能:從Fragment01的介面跳到Fragment02,然後按Back鍵,會返回到Fragment01。這個功能該怎麼實現呢?這其實就利用到了返回棧的知識。
其實很簡單,FragmentTransaction中提供了一個addToBackStack()方法,可以將一個事務新增到返回棧中。
我們先回顧一下之前動態載入Fragment的程式碼,然後在此基礎之上,增加一行程式碼就可以將Fragment新增到返回棧中:(即第07行程式碼)
//步驟一:新增一個FragmentTransaction的例項 FragmentManager fragmentManager =getFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); //步驟二:用add()方法加上Fragment的物件 RightFragment rightFragment = new RightFragment(); transaction.add(R.id.right, rightFragment); transaction.addToBackStack(null); //步驟三:呼叫commit()方法使得FragmentTransaction例項的改變生效 transaction.commit();
第07行程式碼:我們在事務提交之前呼叫了FragmentTransaction的addToBackStack()方法,它可以接受一個名字用於描述返回棧的狀態,,一般傳入null即可。
【例項】現在通過程式碼來實現以下介面(下面的圖片為程式執行時載入的首頁),並且把每一個Fragment都加入到返回棧當中去,然後觀察其生命週期的變化。完整程式碼如下:
首先新建工程檔案m01_Fragment04,然後開始我們的程式碼之旅:
我們先把右側的四個Fragment建起來吧:
Fragment01.java主要部分的程式碼如下:
1 package com.example.m01_fragment04; 2 3 import android.app.Fragment; 4 import android.os.Bundle; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.view.ViewGroup; 8 9 public class Fragment01 extends Fragment { 10 11 @Override 12 public void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 } 15 16 @Override 17 public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 Bundle savedInstanceState) { 19 View view = inflater.inflate(R.layout.f1, null); 20 return view; 21 } 22 @Override 23 public void onPause() { 24 super.onPause(); 25 } 26 }
為避免囉嗦,這裡就不把Fragment01生命週期中的其他函式羅列出來了,我們只要知道在實際程式碼中這些函式都是加了的。
Fragment01的佈局檔案f1.xml的程式碼如下:
<?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" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="載入圖片" /> </LinearLayout>
然後依次新建出Fragment02、Fragment03、Fragment04的java程式碼和佈局檔案。
MainActivity的佈局檔案activity_main.xml程式碼如下:
<LinearLayout 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=".MainActivity" > <LinearLayout android:id="@+id/left" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="#CCCCCC" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="載入圖片" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="海報管理" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="照片管理" /> <Button android:id="@+id/button4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新聞管理" /> </LinearLayout> <LinearLayout android:id="@+id/right" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" > </LinearLayout> </LinearLayout>
其中,第一個LinearLayout表示左側的按鈕,第二個LinearLayout留給右邊的Fragment。
MainActivity.java的程式碼如下:
1 package com.example.m01_fragment04; 2 3 import android.os.Bundle; 4 import android.app.Activity; 5 import android.app.FragmentManager; 6 import android.app.FragmentTransaction; 7 import android.view.Menu; 8 import android.view.View; 9 import android.view.View.OnClickListener; 10 import android.widget.Button; 11 12 public class MainActivity extends Activity implements OnClickListener{ 13 14 private FragmentManager manager; 15 private FragmentTransaction transaction; 16 private Button button1,button2,button3,button4; 17 18 @Override 19 protected void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 23 manager = getFragmentManager(); 24 button1 = (Button)this.findViewById(R.id.button1); 25 button1.setOnClickListener(this); 26 button2 = (Button)this.findViewById(R.id.button2); 27 button2.setOnClickListener(this); 28 button3 = (Button)this.findViewById(R.id.button3); 29 button3.setOnClickListener(this); 30 button4 = (Button)this.findViewById(R.id.button4); 31 button4.setOnClickListener(this); 32 33 } 34 35 @Override 36 public boolean onCreateOptionsMenu(Menu menu) { 37 // Inflate the menu; this adds items to the action bar if it is present. 38 getMenuInflater().inflate(R.menu.main, menu); 39 return true; 40 } 41 42 //通過點選不同的按鈕,跳轉到不同的Fragment 43 @Override 44 public void onClick(View v) { 45 // TODO Auto-generated method stub 46 transaction = manager.beginTransaction(); 47 switch (v.getId()) { 48 case R.id.button1: 49 Fragment01 fragment01 = new Fragment01(); 50 transaction.replace(R.id.right, fragment01, "fragment01"); 51 transaction.addToBackStack("fragment01");// 新增到Activity管理的回退棧中。 52 break; 53 54 case R.id.button2: 55 Fragment02 fragment02 = new Fragment02(); 56 transaction.replace(R.id.right, fragment02, "fragment02"); 57 transaction.addToBackStack("fragment02");// 新增到Activity管理的回退棧中。 58 break; 59 60 case R.id.button3: 61 Fragment03 fragment03 = new Fragment03(); 62 transaction.replace(R.id.right, fragment03, "fragment03"); 63 transaction.addToBackStack("fragment03");// 新增到Activity管理的回退棧中。 64 break; 65 66 case R.id.button4: 67 Fragment04 fragment04 = new Fragment04(); 68 transaction.replace(R.id.right, fragment04, "fragment04"); 69 transaction.addToBackStack("fragment04");// 新增到Activity管理的回退棧中。 70 break; 71 } 72 transaction.commit(); 73 } 74 75 }
上當程式碼中,通過點選不同的按鈕,就能跳到對應的Fragment,而這四個Fragment都已經加入到了返回棧當中。執行程式之後,也是這樣的。
注意第46行和第72行,transaction = manager.beginTransaction()意味著開始,transaction.commit()意味著結束。
我們就其中的fragment01和fragment02來討論一下他們的生命週期的變化:
執行程式後,介面如下,沒有任何fragment被載入:
點選左側第一個按鈕,載入fragment01:
點選左側第二個按鈕,載入fragment02(此時fragment01被替換,並被壓到了棧當中):
注:如果fragment01在替換的時候沒有被壓到棧中,那就會被銷燬,在執行完onDestroyView()方法後,會繼續執行onDestroy()和onDetach()方法。
按Back鍵,fragment01重新返回到螢幕:(fragment02被銷燬)
再按Back鍵,fragment01被銷燬:
注:Fragment的返回棧由Activity管理;而Activity的返回棧由系統管理。
相關文章
- Fragment的生命週期Fragment
- Fragment生命週期Fragment
- Android Fragment生命週期深入探究AndroidFragment
- Android | Activity和Fragment最全生命週期+發現大牛AndroidFragment
- Fragment 生命週期的詳情Fragment
- 關於Fragment的生命週期Fragment
- Android Fragment生命週期——多螢幕支援AndroidFragment
- Fragment生命週期筆記Fragment筆記
- fragment生命週期(總結)Fragment
- Flutter路由棧和生命週期解析Flutter路由
- [Android]Activity的生命週期Android
- Android MediaPlayer的生命週期Android
- android:碎片的生命週期Android
- HarmonyOS 應用生命週期有哪些? 按返回鍵會呼叫哪些生命週期?
- [譯] android應用開發者,你們真的瞭解Fragment的生命週期嗎?AndroidFragment
- Android Activity生命週期Android
- 關於Fragment可見與不可見時的生命週期Fragment
- 品牌生命週期和產品生命週期之間的關係
- Activity 生命週期和棧(Task)的關係及Intent 常用的FlagsIntent
- View和Activity的生命週期View
- Android之各生命週期Android
- Android Activit生命週期方法Android
- 2018.03.05 Android 記一次關於Fragment生命週期的討論。AndroidFragment
- Android View的生命週期詳解AndroidView
- React 渲染 和 生命週期React
- Android Activity的生命週期和啟動模式詳解Android模式
- View生命週期與Activity生命週期的關係View
- activity生命週期的onPause和onStop
- Android Service生命週期淺析Android
- Android 元件系列-----Activity生命週期Android元件
- Android Activity生命週期詳解Android
- Android程式生命週期ProcessLifecycleAndroid
- 生命週期
- Android Activity生命週期的一點感悟Android
- Android:聊聊 MVP 中 Presenter 的生命週期AndroidMVP
- 初識Android之Activity的生命週期Android
- android Activity A和B互相跳轉 生命週期的變化Android
- MyBatis 作用域和生命週期MyBatis