Android初级开发笔记 -- 关于Fragment的回退栈

一直想好好研究一下项目中经常用到的Fragment。这篇先记录一下对Fragment的回退栈的学习。
@[toc]

一、什么是Fragment

Fragment是Android3.0之后引入的可嵌入activity中的碎片化组件,实现了界面的最大化利用。有以下几个特点:
(1)不可独立存在,但是有自己的生命周期。不过因为与activity关联在一起,生命周期会受activity影响。
(2) 可静态引入也可动态加载。推荐使用support-v4中的android.support.v4.app.Fragment而非系统内置的android.app.Fragment。因前者能让Fragment在所有Android系统版本中保持功能一致性。

二、Fragment的生命周期

  • 先po一张经典生命周期图:


    在这里插入图片描述

    我们可以看到有几个关键的回调方法。

onAttach()
Fragment和Activity建立关联的时候调用(获得activity的传递的值)

onCreateView()
为Fragment创建视图(加载布局)时调用(给当前的fragment绘制UI布局)

onActivityCreated()
当Activity中的onCreate方法执行完后调用(表示activity执行oncreate方法完成了的时候会调用此方法)

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的回退栈有关啦~

三、实例讲述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的合体,视图重绘

总结

1、replace,加回退栈 --- Fragment不销毁,但是切换时会销毁视图和重新创建视图

2、replace, 不加回退栈 --- Fragment销毁

3、hide、show --- Fragment不销毁,也不销毁视图。隐藏和显示不走生命周期

四、结语

未完待续~毕竟Fragment还有很多要学的东西

然后还是那句老话,希望各位看官不吝赐教~蟹蟹啦

内推信息

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,063评论 6 510
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,805评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,403评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,110评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,130评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,877评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,533评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,429评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,947评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,078评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,204评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,894评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,546评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,086评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,195评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,519评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,198评论 2 357

推荐阅读更多精彩内容