Android初級開發筆記 -- 關於Fragment的回退棧

一直想好好研究一下項目中常常用到的Fragment。這篇先記錄一下對Fragment的回退棧的學習。 @[toc]java

1、什麼是Fragment

Fragment是Android3.0以後引入的可嵌入activity中的碎片化組件,實現了界面的最大化利用。有如下幾個特色:android

(1)不可獨立存在,可是有本身的生命週期。不過由於與activity關聯在一塊兒,生命週期會受activity影響。app

(2) 可靜態引入也可動態加載。推薦使用support-v4中的android.support.v4.app.Fragment而非系統內置的android.app.Fragment。因前者能讓Fragment在全部Android系統版本中保持功能一致性。ide

2、Fragment的生命週期

  • 先po一張經典生命週期圖:
    在這裏插入圖片描述
    咱們能夠看到有幾個關鍵的回調方法。

onAttach()佈局

Fragment和Activity創建關聯的時候調用(得到activity的傳遞的值)學習

onCreateView()this

爲Fragment建立視圖(加載佈局)時調用(給當前的fragment繪製UI佈局)spa

onActivityCreated()code

當Activity中的onCreate方法執行完後調用(表示activity執行oncreate方法完成了的時候會調用此方法)cdn

onDestroyView()

Fragment中的佈局被移除時調用(表示fragment銷燬相關聯的UI佈局)

onDetach()

Fragment和Activity解除關聯的時候調用(脫離activity)

  • 不一樣狀況下的方法回調

當一個fragment第一次被加載到屏幕上的時候,會依次執行:

onAttach()

onCreate()

onCreateView()

onActivityCreated()

接着,當這個fragment對用戶可見的時候,會依次執行:

onStart()

onResume()

這個時候,若是該fragment進入了中止狀態(「進入後臺模式」),會依次執行:

onPause()

onStop()

若這個fragment被銷燬了(或者和ta關聯的activity被銷燬了),在執行了上面兩個方法以後緊跟着會執行:

onDestroyView()

onDestroy()

onDetach()

此時該fragment被銷燬而且與activity解除了關聯。

  • 前面咱們說到,fragment的生命週期受到ta關聯的activity的生命週期的影響~ 影響有多大呢?看圖說話~
    在這裏插入圖片描述
    好了,那麼若是該fragment沒有被銷燬呢?當ta又從新回到了運行狀態,會依次執行:

onCreateView()

onActivityCreated()

onStart()

onResume()

由於沒有被銷燬,因此onCreate()不會被調用。

額那什麼狀況下fragment沒有被銷燬呢?這就和fragment的回退棧有關啦~

3、實例講述Fragment回退棧

咱們知道Activity是以棧的方式進行管理的,Fragment也有相似的方式。

Fragment的回退棧---是用來保存每一次Fragment事務發生的變化 若是你將Fragment任務添加到回退棧,當用戶點擊後退按鈕時,將看到上一次的保存的Fragment。一旦Fragment徹底從後退棧中彈出,用戶再次點擊後退鍵,則退出當前Activity。

首先咱們先認識下這個方法:FragmentTransaction.addToBackStack(String)【把當前事務的變化狀況添加到回退棧,通常傳入null便可】

接下來咱們用一個例子來證實一下其起到的做用以及生命週期是否真的有所不一樣。

MainActivity的佈局文件

<RelativeLayout 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" >  

    <FrameLayout  
        android:id="@+id/id_content"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent" >  
    </FrameLayout>  

</RelativeLayout>
複製代碼

MainActivity.java文件

public class MainActivity extends Activity {  

    protected void onCreate(Bundle savedInstanceState){  
        super.onCreate(savedInstanceState);  
        requestWindowFeature(Window.FEATURE_NO_TITLE);  
        setContentView(R.layout.activity_main);  

        FragmentManager fm = getFragmentManager();  
        FragmentTransaction tx = fm.beginTransaction();  
        tx.add(R.id.id_content, new FragmentOne(),"ONE");  
        tx.commit();  
    }  
}
複製代碼

FragmentOne.class文件

public class FragmentOne extends Fragment implements OnClickListener {  

    private Button mBtn;  

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        View view = inflater.inflate(R.layout.fragment_one, container, false);  
        mBtn = (Button) view.findViewById(R.id.bn_fragment_one);  
        mBtn.setOnClickListener(this);  
        Log.e("onCreateView", "one");
        return view;  
    }  

    @Override  
    public void onClick(View v) {  
        FragmentTwo fTwo = new FragmentTwo();  
        FragmentManager fm = getFragmentManager();  
        FragmentTransaction tx = fm.beginTransaction();  
        tx.replace(R.id.id_content, fTwo, "TWO");  
        tx.addToBackStack(null); 
        tx.commit();  
    }  
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.e("onAttach", "one");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e("onCreate", "one");
    }


    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.e("onActivityCreated", "one");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.e("onStart", "one");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.e("onResume", "one");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.e("onPause", "one");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.e("onStop", "one");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("onDestroy", "one");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.e("onDetach", "one");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.e("onDestroyView", "one");
    }
複製代碼

FragmentTwo.class文件

public class FragmentTwo extends Fragment implements OnClickListener {  

    private Button mBtn ;  

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        View view = inflater.inflate(R.layout.fragment_two, container, false);  
        mBtn = (Button) view.findViewById(R.id.bn_fragment_two);  
        mBtn.setOnClickListener(this);  
        Log.e("onCreateView", "two");
        return view ;   
    }  

    @Override  
    public void onClick(View v) {  
        FragmentThree fThree = new FragmentThree();  
        FragmentManager fm = getFragmentManager();  
        FragmentTransaction tx = fm.beginTransaction();  
        tx.hide(this);  
        tx.add(R.id.id_content , fThree, "THREE");  
        //tx.replace(R.id.id_content, fThree, "THREE"); 
        tx.addToBackStack(null);  
        tx.commit();  
    }  

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.e("onAttach", "two");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e("onCreate", "two");
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.e("onActivityCreated", "two");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.e("onStart", "two");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.e("onResume", "two");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.e("onPause", "two");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.e("onStop", "two");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("onDestroy", "two");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.e("onDetach", "two");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.e("onDestroyView", "two");
    }
複製代碼

FragmentThree.class文件

public class FragmentThree extends Fragment implements OnClickListener {  

    private Button mBtn;  

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        View view = inflater.inflate(R.layout.fragment_three, container, false);  
        mBtn = (Button) view.findViewById(R.id.bn_fragment_three);  
        mBtn.setOnClickListener(this);  
        Log.e("onCreateView", "three");
        return view;  
    }  

    @Override  
    public void onClick(View v) {  
        Toast.makeText(getActivity(), " i am a btn in Fragment three",  
                Toast.LENGTH_SHORT).show();  
    }  
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.e("onAttach", "three");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e("onCreate", "three");
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.e("onActivityCreated", "three");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.e("onStart", "three");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.e("onResume", "three");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.e("onPause", "three");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.e("onStop", "three");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("onDestroy", "three");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.e("onDetach", "three");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.e("onDestroyView", "three");
    }
複製代碼

R.layout.fragment_one文件

<?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">

    <EditText
        android:id="@+id/et_fragment_one"
        android:layout_width="match_parent"
        android:text="myself"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/bn_fragment_one"
        android:layout_width="wrap_content"
        android:text="Button in one"
        android:layout_height="wrap_content" />
</LinearLayout>
複製代碼

這個過程當中所調用的回調方法,Log打印以下:

在這裏插入圖片描述
在從FragmentOne跳轉到FragmentTwo的時候,代碼以下:

@Override
    public void onClick(View v) {
        FragmentTwo fTwo = new FragmentTwo();
        FragmentManager fm = getFragmentManager();
        FragmentTransaction tx = fm.beginTransaction();
        tx.replace(R.id.id_content, fTwo, "TWO");
        tx.addToBackStack(null);
        tx.commit();
    }
複製代碼

此時FragmentOne被替換【replace】,添加到回退棧中【addToBackStack】,onPause(),onStop(),onDestroyView()被調用,可是onDestroy(),onDetach()就沒被調用,該Fragment實例被保存了下來。Log:

在這裏插入圖片描述
在從FragmentTwo跳轉到FragmentThree的時候
在這裏插入圖片描述
第一次返回,因爲FragmentThree並無被保存到回退棧中,因此會調用到onDestroy(),onDetach()方法
在這裏插入圖片描述
第二次返回,從FragmentTwo返回到FragmentOne,因爲FragmentOne實例仍在,因此沒有調用onCreate()
在這裏插入圖片描述
第三次返回,回到桌面
在這裏插入圖片描述
有沒有發現,在從FragmentTwo跳轉到FragmentThree的以及從新回到FragmentTwo的時候,並無調用到FragmentTwo任何回調方法?是的沒有錯就是這樣。 由於從FragmentTwo到FragmentThree的代碼是這樣寫的:

@Override
    public void onClick(View v) {
        FragmentThree fThree = new FragmentThree();
        FragmentManager fm = getFragmentManager();
        FragmentTransaction tx = fm.beginTransaction();
        tx.hide(this);
        tx.add(R.id.id_content , fThree, "THREE");
        //tx.replace(R.id.id_content, fThree, "THREE");
        tx.addToBackStack(null);
        tx.commit();
    }
複製代碼

調用的是hide(),而非replace()

區別

hide(),show():調用了Fragment建立及到前臺的幾個回調方法後,該Fragment在後臺或者從新回到前臺的時候,不會調用到相關生命週期回調方法,因此視圖不會重繪

replace():至關於remove和add的合體,視圖重繪

總結

一、replace,加回退棧 --- Fragment不銷燬,可是切換時會銷燬視圖和從新建立視圖

二、replace, 不加回退棧 --- Fragment銷燬

三、hide、show --- Fragment不銷燬,也不銷燬視圖。隱藏和顯示不走生命週期

4、結語

未完待續~畢竟Fragment還有不少要學的東西

而後仍是那句老話,但願各位看官不吝賜教~蟹蟹啦

相關文章
相關標籤/搜索