Fragment 的 聲明周期、回退棧等

前言

正文

一、Fragment 的由來(lái)

Fragment 是在 Android 3.0 之后引入的,主要是為了解決手機(jī)和屏幕的適配問題,同時(shí),也能相應(yīng)解決 activity 中代碼量過大的問題,不過,從 Fragment 問世以來(lái),相關(guān)的爭(zhēng)論就不斷,有同意使用的,也有反對(duì)使用的,反對(duì)的大部分原因就是坑太多,不好用,但是就我來(lái)看,用的人還是很多,而且本人也在經(jīng)常使用,所以就來(lái)篇 Fragment 的大總結(jié)。

二、Fragment 的生命周期

Fragment 是嵌套在 Activity 中使用的,生命周期也與 Activity 極其相似,除了與 Activity 相同的幾個(gè)生命周期方法之外,另加了幾個(gè)與 Activity 相交互的幾個(gè)方法,如下圖所示:

image

幾個(gè)額外的方法的介紹如下:

  • onAttach(Context context) :當(dāng) Fragment 與 Activity 發(fā)生關(guān)聯(lián)的時(shí)候調(diào)用,( Activity 傳遞到此方法內(nèi))

    此方法內(nèi)部還是調(diào)用的 onAttach(Activity activity) 方法

  • onCreateView ( LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState )

    創(chuàng)建 Fragment 視圖的時(shí)候調(diào)用,

  • onViewCreated(View view, @Nullable Bundle savedInstanceState)

    在 Activity 的 onCreate() 方法已返回時(shí)調(diào)用。

  • onDestroyView()

    與 onCreateView 對(duì)應(yīng),當(dāng)該 Fragment 的視圖被移除時(shí)調(diào)用

  • onDetach()

    與 onAttach 相對(duì)應(yīng),當(dāng) Fragment 與 Activity 關(guān)聯(lián)被取消時(shí)調(diào)用

三、不同包下的 Fragment 的區(qū)別

Fragment 分兩個(gè)不同包下:

android.support.v4.app.Fragment;

android.app.Fragment;

區(qū)別如下:

  1. 兼容版本不同
    v4 包下的是為了兼容之 1.6 系統(tǒng)。
    另一個(gè)包下的是兼容 3.0 以上系統(tǒng)。不過這個(gè)現(xiàn)在沒啥用了,因?yàn)楝F(xiàn)在的手機(jī)基本都在 4.0 以上了
  1. 大家都知道 Fragment 是嵌套在 Activity 中使用的,對(duì) Activity 的要求不同
    v4 包下的就要求這個(gè) Activity 必須繼承自FragmentActivity
    另一個(gè)包下的不要求,其中 FragmentActivity 集成自 Activity

  2. 獲取 FragmentManager 的方式不同

    v4 包下的是通過:getSupportFragmentManager();
    另一個(gè)包下的是:getFragmentManager();

注意:
關(guān)于 Fragment 的一切都要配套使用,注意導(dǎo)包問題否則容易出現(xiàn)類似這種錯(cuò)誤: wrong 2nd argument type found 'android.app.Fragment.' required 'Android.support.v4.app.Fragment'

四、Fragment 常用 API

  1. FragmentManager

    這是 Fragment 管理者,要想操作 Fragment 必須先獲取管理者,根據(jù)不同的包,有兩種獲取方式:getFragmentManager() // v4 中,getSupportFragmentManager

  2. FragmentTransaction

    所有的操作都是基于此類的,調(diào)用此類的一系列方法來(lái)管理 Fragment ,
    獲取方式:fragmentManager.beginTransaction();方法大致如下:

  • add()

    往Activity中添加一個(gè)Fragment

  • remove()

    從 Activity 中移除一個(gè) Fragment,如果被移除的 Fragment 沒有添加到回退棧這個(gè) Fragment 實(shí)例將會(huì)被銷毀。

  • replace()

    使用另一個(gè) Fragment 替換當(dāng)前的,實(shí)際上就是 remove() 和 add() 的合體

  • hide()

    隱藏當(dāng)前的 Fragment,僅僅是設(shè)為不可見,并不會(huì)銷毀

  • show()

    顯示之前隱藏的 Fragment

  • detach()

    會(huì)將 view 從 UI 中移除,和 remove() 不同,此時(shí) fragment 的狀態(tài)依然由 FragmentManager 維護(hù)。

  • attach()

    重建 view 視圖,附加到 UI 上并顯示。

  • commit()

    提交一個(gè)事務(wù),此方法必須要在 Activity 的 onSaveInstanceState 方法之前調(diào)用

五、使用 Fragment 的最簡(jiǎn)單的操作

1. 兩個(gè) Fragment
public class FirstFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        
        View inflate = inflater.inflate(R.layout.firstfragment_layout, container, false);
        return inflate;
    }
public class SecondFragment extends Fragment {
    
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View inflate = inflater.inflate(R.layout.secondfragment_layout, container, false);
        return inflate;
    }
2. Activity 中
public class MainActivity extends AppCompatActivity {


    @BindView(R.id.btn)
    Button btn;
    @BindView(R.id.fragment)
    FrameLayout fragment;
    private FragmentManager fragmentManager;
    private FirstFragment firstFragment;
    private FragmentTransaction fragmentTransaction;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        
        setDefaultFragment();
    }

    /**
     * 設(shè)置默認(rèn)的 fragment
     */
    private void setDefaultFragment() {

        fragmentManager = getSupportFragmentManager();
        fragmentTransaction = fragmentManager.beginTransaction();
        firstFragment = new FirstFragment();
        fragmentTransaction.add(R.id.fragment, firstFragment, "first").commit();
    }


    @OnClick(R.id.btn)
    public void onViewClicked() {

        FragmentManager supportFragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction1 = supportFragmentManager.beginTransaction();
        SecondFragment secondFragment = new SecondFragment();
        fragmentTransaction1.replace(R.id.fragment, secondFragment, "second");
        fragmentTransaction1.commit();
    }
}
3. activity 中的 xml 文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.administrator.fragment_text.MainActivity">

    <FrameLayout
        android:id="@+id/fragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
>

    </FrameLayout>

</LinearLayout>

點(diǎn)擊按鈕之后就能切換 Fragment

六、 Fragment 回退棧 ( 包含 Fragment 常用 API 調(diào)用生命周期方法詳解 )

  • 個(gè)人對(duì)回退棧的理解為: 當(dāng) Fragment 入棧之后,能夠保存此 Fragment 的狀態(tài),通過返回鍵再次回到此 Fragment 的時(shí)候,數(shù)據(jù)依然存在!

  • 回退棧就像 Activity 一樣,先進(jìn)后出,一層一層的

  • 由于是真機(jī)測(cè)試,所以沒法提供動(dòng)圖

  • 測(cè)試邏輯大概是這樣的:三個(gè) Fragment 按順序跳轉(zhuǎn),每個(gè) Fragment 中都有一個(gè)輸入框,測(cè)試是否能保存輸入框中的內(nèi)容,及調(diào)用的生命周期方法。

1. 三個(gè) Fragment 分別為:
  • FirstFragment
package com.example.administrator.fragment_text.huituizhan;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

import com.example.administrator.fragment_text.R;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;


/**
 * Created by Administrator on 2017/4/10.
 */

public class FirstFragment extends Fragment {

    @BindView(R.id.editText)
    EditText editText;
    @BindView(R.id.btn)
    Button btn;
    Unbinder unbinder;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        Log.i("FirstFragment","onCreateView");
        View inflate = inflater.inflate(R.layout.huituizhan_first_fragment, container, false);
        unbinder = ButterKnife.bind(this, inflate);
        return inflate;
    }

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

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

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Log.i("FirstFragment","onViewCreated");
        super.onViewCreated(view, savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.i("FirstFragment","onStart");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.i("FirstFragment","onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.i("FirstFragment","onPause");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.i("FirstFragment","onStop");
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        Log.i("FirstFragment","onDestroyView");
        super.onDestroyView();
        unbinder.unbind();
    }

    @Override
    public void onDestroy() {
        Log.i("FirstFragment","onDestroy");
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        Log.i("FirstFragment","onDetach");
        super.onDetach();
    }
    /**
     * 點(diǎn)擊按鈕切換到 SecondFragment 
     */
    @OnClick(R.id.btn)
    public void onViewClicked() {

        FragmentManager fragmentManager = getFragmentManager();

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        SecondFragment secondFragment = new SecondFragment();

        fragmentTransaction.hide(this);
        fragmentTransaction.add(R.id.framelayout,secondFragment,"second");
        // 將 FirstFragment 添加至 回退棧
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();


    }
}

注意此處切換 Fragment 使用的是:

fragmentTransaction.hide(this);
fragmentTransaction.add(R.id.framelayout,secondFragment,"second");
  • SecondFragment
package com.example.administrator.fragment_text.huituizhan;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

import com.example.administrator.fragment_text.R;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;


/**
 * Created by Administrator on 2017/4/10.
 */

public class SecondFragment extends Fragment {

    @BindView(R.id.editText)
    EditText editText;
    @BindView(R.id.btn)
    Button btn;
    Unbinder unbinder;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View inflate = inflater.inflate(R.layout.huituizhan_second_fragment, container, false);
        unbinder = ButterKnife.bind(this, inflate);
        Log.i("SecondFragment","onCreateView");
        return inflate;
    }

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

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

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Log.i("SecondFragment","onViewCreated");
        super.onViewCreated(view, savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.i("SecondFragment","onStart");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.i("SecondFragment","onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.i("SecondFragment","onPause");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.i("SecondFragment","onStop");
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        Log.i("SecondFragment","onDestroyView");
        super.onDestroyView();
        unbinder.unbind();
    }

    @Override
    public void onDestroy() {
        Log.i("SecondFragment","onDestroy");
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        Log.i("SecondFragment","onDetach");
        super.onDetach();
    }

    @OnClick(R.id.btn)
    public void onViewClicked() {
        FragmentManager fragmentManager = getFragmentManager();

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        ThreeFragment threeFragment = new ThreeFragment();
        fragmentTransaction.replace(R.id.framelayout,threeFragment,"three");
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
    }
}

注意此處切換 Fragment 使用的是:

 fragmentTransaction.replace(R.id.framelayout,threeFragment,"three");
  • ThreeFragment
package com.example.administrator.fragment_text.huituizhan;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.example.administrator.fragment_text.R;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;


/**
 * Created by Administrator on 2017/4/10.
 */

public class ThreeFragment extends Fragment {

    @BindView(R.id.editText)
    EditText editText;
    @BindView(R.id.btn)
    Button btn;
    Unbinder unbinder;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View inflate = inflater.inflate(R.layout.huituizhan_three_fragment, container, false);
        unbinder = ButterKnife.bind(this, inflate);
        return inflate;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }

    @OnClick({R.id.editText, R.id.btn})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.editText:
                break;
            case R.id.btn:
                Toast.makeText(getActivity().getApplicationContext(),"最后一個(gè)了",Toast.LENGTH_SHORT)
                        .show();
                break;
        }
    }
}

2. Activity 中的代碼為:
package com.example.administrator.fragment_text.huituizhan;

import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.widget.FrameLayout;

import com.example.administrator.fragment_text.R;

import butterknife.BindView;
import butterknife.ButterKnife;

public class HuiTuiZhanActivity extends AppCompatActivity {

    @BindView(R.id.framelayout)
    FrameLayout framelayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hui_tui_zhan);
        ButterKnife.bind(this);

        FragmentManager supportFragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();

        FirstFragment firstFragment = new FirstFragment();

        fragmentTransaction.add(R.id.framelayout,firstFragment,"first").commit();

    }
}

3. 運(yùn)行之后,hide、add 與 replace 都能保存數(shù)據(jù),但是生命周期不太一樣,如下所示:
  • FirstFragment 跳轉(zhuǎn)到 SecondFragment 時(shí):
04-22 13:43:10.160 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onAttach
04-22 13:43:10.160 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onCreate
04-22 13:43:10.160 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onCreateView
04-22 13:43:10.180 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onViewCreated
04-22 13:43:10.180 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStart
04-22 13:43:10.180 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onResume
04-22 13:43:26.605 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onAttach
04-22 13:43:26.605 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onCreate
04-22 13:43:26.615 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onCreateView
04-22 13:43:26.620 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onViewCreated
04-22 13:43:26.620 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStart
04-22 13:43:26.620 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onResume

注意: 此處切換的時(shí)候,沒有立馬調(diào)用 FirstFragment 的 onPause、onStop、onDestroyView

  • SecondFragment 跳轉(zhuǎn)到 ThreeFragment 時(shí):
04-22 13:45:22.035 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onPause
04-22 13:45:22.035 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStop
04-22 13:45:22.035 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDestroyView
04-22 13:45:22.040 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onPause
04-22 13:45:22.040 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStop
04-22 13:45:22.040 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDestroyView

注意:此處是先調(diào)用 SecondFragment 的 onPause、onStop、onDestroyView,然后才調(diào)用 FirstFragment 的對(duì)應(yīng)方法,

  • 按返回鍵 ThreeFragment 回退到 SecondFragment 時(shí):
04-22 13:51:26.075 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onCreateView
04-22 13:51:26.085 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onViewCreated
04-22 13:51:26.090 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStart
04-22 13:51:26.090 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onResume
04-22 13:51:26.095 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onCreateView
04-22 13:51:26.100 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onViewCreated
04-22 13:51:26.100 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStart
04-22 13:51:26.100 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onResume

注意: 此處竟然先調(diào)用的是 FirstFragment 的 onCreateView、onViewCreated、onStart、onResume

  • 繼續(xù)按返回鍵 SecondFragment 回退到 FirstFragment 時(shí):
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onPause
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStop
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDestroyView
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDestroy
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDetach

  • 繼續(xù)返回鍵 退出 Activity 時(shí):
04-22 13:53:33.675 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onPause
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStop
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDestroyView
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDestroy
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDetach

4. Fragment 退棧方式

這有個(gè)哥們寫的非常詳細(xì):http://blog.csdn.net/u010049692/article/details/38944867

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容