tab+Fragment管理最佳实践

现在的app视图中tab+fragment是比较常用的一种UI主界面布局方式–多个叶签切换、不需要左右滑动并且所有页面视图都预加载,但是如果使用才是更简洁更有效的呢?下面通过一个demo的分类测试来分析下:

add remove replace detach attach hide show这些方法的使用对Fragment生命周期的影响分析:
顺便分析下Fragment所依赖的Activity的生命周期;

测试代码如下:
MainActivity的代码如下:

package com.testfragmentlifecircle;

import android.content.Intent;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends FragmentActivity {
    private static final String TAG = "test-MainActivity";

    // 首页
    private IndexFragment indexFragment;
    // 我的页面
    private MineFragment mineFragment;
    // 更多页面
    private MoreFragment moreFragment;
    private TextView[] textviews;
    private Fragment[] fragments;
    public int index;
    // 当前fragment的index
    private int currentTabIndex;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "--onCreate");
        setContentView(R.layout.activity_main);

        initView();
    }

    private void initView() {
        textviews = new TextView[3];
        textviews[0] = (TextView) findViewById(R.id.index_text);
        textviews[1] = (TextView) findViewById(R.id.mine_text);
        textviews[2] = (TextView) findViewById(R.id.more_text);
        textviews[0].setSelected(true);
        indexFragment = new IndexFragment();
        mineFragment = new MineFragment();
        moreFragment = new MoreFragment();
        fragments = new Fragment[]{indexFragment, mineFragment, moreFragment};
        // 添加显示第一个fragment
        /*用add、hide和show测试的初始化的代码*/
//        getSupportFragmentManager().beginTransaction()
//                .add(R.id.fragment_container, indexFragment)
//                .add(R.id.fragment_container, mineFragment)
//                .add(R.id.fragment_container, moreFragment)
//                .show(indexFragment).hide(mineFragment).hide(moreFragment)
//                .commit();
        /*用replace测试的初始化的代码*/
//        getSupportFragmentManager().beginTransaction()
//                .replace(R.id.fragment_container, indexFragment)
//                .addToBackStack(null)
//                .commit();
        /*用attach和dettach测试的初始化的代码*/
        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container, indexFragment)
                .add(R.id.fragment_container, mineFragment)
                .add(R.id.fragment_container, moreFragment)
                .attach(indexFragment)
                .detach(mineFragment)
                .detach(moreFragment)
                .commit();
    }

    private void refreshTab() {
        if (currentTabIndex != index) {
            FragmentTransaction trx = getSupportFragmentManager()
                    .beginTransaction();
            /*用add、hide和show测试的切换Fragment的代码*/
//            for (int i = 0; i < fragments.length; i++) {
//                if (!fragments[i].isAdded()) {
//                    trx.add(R.id.fragment_container, fragments[i]);
//                }
//                if (i != index) {
//                    trx.hide(fragments[i]);
//                } else {
//                    trx.show(fragments[i]);
//                }
//            }
            /*用replace测试的切换Fragment的代码*/
//            trx.addToBackStack(null);
//            trx.replace(R.id.fragment_container, fragments[index]);
            /*用attach和dettach测试的切换Fragment的代码*/
            for (int i = 0; i < fragments.length; i++) {
                if (!fragments[i].isAdded()) {
                    trx.add(R.id.fragment_container, fragments[i]);
                }
                if (i != index) {
                    trx.detach(fragments[i]);
                } else {
                    trx.attach(fragments[i]);
                }
            }
            trx.commit();

            textviews[currentTabIndex].setSelected(false);
            textviews[index].setSelected(true);
            currentTabIndex = index;
        }
    }

    public void onTabClicked(View view) {
        switch (view.getId()) {
            case R.id.index:
                if (0 != index) {
                    index = 0;
                }
                break;
            case R.id.mine:
                if (1 != index) {
                    index = 1;
                }
                break;
            case R.id.more:
                if (2 != index) {
                    index = 2;
                }
                break;
        }
        refreshTab();
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        Log.e(TAG, "--onBackPressed");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "--onDestroy");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "--onPause");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "--onResume");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.e(TAG, "--onNewIntent");
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        Log.e(TAG, "--onPostResume");
    }

    @Override
    protected void onResumeFragments() {
        super.onResumeFragments();
        Log.e(TAG, "--onResumeFragments");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG, "--onSaveInstanceState");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "--onStart");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "--onStop");
    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        Log.e(TAG, "--onAttachFragment");
    }

}

BaseFragment代码如下:

package com.testfragmentlifecircle;

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

/**
 * 作 者: yc
 * 创 建:2016/4/27-11:52
 * 版 本:
 */
public class BaseFragment extends Fragment {

    protected final String TAG = "test-" + this.getClass().getSimpleName();

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

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

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.e(TAG,"--onCreateView");
        TextView textView = new TextView(getContext());
        textView.setText(TAG);
        return textView;
    }

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

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

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

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

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

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.e(TAG,"--onDestroyView");
    }

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

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

    @Override
    public void onHiddenChanged(boolean hidden) {
        Log.e(TAG,"--onHiddenChanged--hidden="+hidden);
        super.onHiddenChanged(hidden);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG,"--onSaveInstanceState");
    }
}

三个Fragment分别为IndexFragment、MineFragment和MoreFragment,代码分别如下:

package com.testfragmentlifecircle;

/**
 * 作 者: yc
 * 创 建:2016/4/27-12:36
 * 版 本:
 */
public class IndexFragment extends BaseFragment {

}
package com.testfragmentlifecircle;

/**
 * 作 者: yc
 * 创 建:2016/4/27-12:36
 * 版 本:
 */
public class MineFragment extends BaseFragment {

}
package com.testfragmentlifecircle;

/**
 * 作 者: yc
 * 创 建:2016/4/27-12:36
 * 版 本:
 */
public class MoreFragment extends BaseFragment {

}

MainActivity布局activity_main.xml代码如下:

<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"
    android:orientation="vertical"
    android:background="@color/other_bg"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/main_bottom"
        android:layout_width="match_parent"
        android:layout_height="48dip"
        android:layout_alignParentBottom="true"
        android:background="@color/index_tab_color"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <RelativeLayout
            android:id="@+id/index"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="onTabClicked"
            android:paddingBottom="2dip"
            android:paddingTop="5dip">

            <TextView
                android:id="@+id/index_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="2dp"
                android:text="@string/index"
                android:textColor="@color/clicked_text_color"
                android:textSize="10sp" />
        RelativeLayout>

        <RelativeLayout
            android:id="@+id/mine"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="onTabClicked"
            android:paddingBottom="2dip"
            android:paddingTop="5dip">

            <TextView
                android:id="@+id/mine_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="2dp"
                android:text="@string/mine"
                android:textColor="@color/clicked_text_color"
                android:textSize="10sp" />
        RelativeLayout>

        <RelativeLayout
            android:id="@+id/more"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="onTabClicked"
            android:paddingBottom="2dip"
            android:paddingTop="5dip">

            <TextView
                android:id="@+id/more_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="2dp"
                android:text="@string/more"
                android:textColor="@color/clicked_text_color"
                android:textSize="10sp" />
        RelativeLayout>
    LinearLayout>

    <View
        android:id="@+id/view_temp"
        android:layout_width="match_parent"
        android:layout_height="0.1dp"
        android:layout_above="@id/main_bottom"
        android:background="@color/index_divider_color" />

    <RelativeLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/view_temp" />

RelativeLayout>

分类测试及日志分析:
1.通过add添加,通过hide和show控制Fragment的隐藏和显示的切换
1.1——————————————-初始化,初始显示IndexFragment,隐藏MineFragment和MoreFragment:
E/test-MainActivity: –onCreate
/com.testfragmentlifecircle E/test-MineFragment: –onHiddenChanged–hidden=true
/com.testfragmentlifecircle E/test-MoreFragment: –onHiddenChanged–hidden=true
/com.testfragmentlifecircle E/test-IndexFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-IndexFragment: –onCreate
/com.testfragmentlifecircle E/test-IndexFragment: –onCreateView
/com.testfragmentlifecircle E/test-IndexFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-MineFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-MineFragment: –onCreate
/com.testfragmentlifecircle E/test-MineFragment: –onCreateView
/com.testfragmentlifecircle E/test-MineFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-MoreFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-MoreFragment: –onCreate
/com.testfragmentlifecircle E/test-MoreFragment: –onCreateView
/com.testfragmentlifecircle E/test-MoreFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
/com.testfragmentlifecircle E/test-MineFragment: –onStart
/com.testfragmentlifecircle E/test-MoreFragment: –onStart
E/test-MainActivity: –onStart
E/test-MainActivity: –onResume
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
/com.testfragmentlifecircle E/test-MineFragment: –onResume
/com.testfragmentlifecircle E/test-MoreFragment: –onResume
E/test-MainActivity: –onResumeFragments
E/test-MainActivity: –onPostResume
结论:初始化隐藏的Fragment会回调onHiddenChanged,初始化显示的不会回调onHiddenChanged,因为add进去的Fragment的默认就是显示的,
所以add之后再调用hide的时候从显示变成了隐藏才会回调onHiddenChanged方法。
结论:onAttachFragment会在每个Fragment关联(onAttach)之后回调,onResumeFragments会在所有Fragment初始化完成之后回调一次
1.2——————————————-退出应用,即退出MainActivity:
E/test-MainActivity: –onBackPressed
/com.testfragmentlifecircle E/test-IndexFragment: –onPause
/com.testfragmentlifecircle E/test-MineFragment: –onPause
/com.testfragmentlifecircle E/test-MoreFragment: –onPause
E/test-MainActivity: –onPause
/com.testfragmentlifecircle E/test-IndexFragment: –onStop
/com.testfragmentlifecircle E/test-MineFragment: –onStop
/com.testfragmentlifecircle E/test-MoreFragment: –onStop
E/test-MainActivity: –onStop
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroyView
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroy
/com.testfragmentlifecircle E/test-IndexFragment: –onDetach
/com.testfragmentlifecircle E/test-MineFragment: –onDestroyView
/com.testfragmentlifecircle E/test-MineFragment: –onDestroy
/com.testfragmentlifecircle E/test-MineFragment: –onDetach
/com.testfragmentlifecircle E/test-MoreFragment: –onDestroyView
/com.testfragmentlifecircle E/test-MoreFragment: –onDestroy
/com.testfragmentlifecircle E/test-MoreFragment: –onDetach
E/test-MainActivity: –onDestroy
结论:走完退出流程
结论:
1.3——————————————-从IndexFragment切换到MineFragment:
/com.testfragmentlifecircle E/test-IndexFragment: –onHiddenChanged–hidden=true
/com.testfragmentlifecircle E/test-MineFragment: –onHiddenChanged–hidden=false
结论:Fragment页面之间通过hide和show进行切换,并不会回调Fragment的任何生命周期方法,只会回调onHiddenChanged
结论:
1.4——————————————-从前台切换到后台:
/com.testfragmentlifecircle E/test-IndexFragment: –onPause
/com.testfragmentlifecircle E/test-MineFragment: –onPause
/com.testfragmentlifecircle E/test-MoreFragment: –onPause
E/test-MainActivity: –onPause
E/test-MainActivity: –onSaveInstanceState
/com.testfragmentlifecircle E/test-IndexFragment: –onStop
/com.testfragmentlifecircle E/test-MineFragment: –onStop
/com.testfragmentlifecircle E/test-MoreFragment: –onStop
E/test-MainActivity: –onStop
结论:当所依赖的MainActivity切换到后台,Fragment同样会执行对应的生命周期方法:onPause–onStop
结论:这里说明一点,这里没有打印这些Fragment的onSaveInstanceState方法的回调,其实这个和MainActivity的执行是一致的
1.5——————————————-从后台切换到前台:
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
/com.testfragmentlifecircle E/test-MineFragment: –onStart
/com.testfragmentlifecircle E/test-MoreFragment: –onStart
E/test-MainActivity: –onStart
E/test-MainActivity: –onResume
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
/com.testfragmentlifecircle E/test-MineFragment: –onResume
/com.testfragmentlifecircle E/test-MoreFragment: –onResume
E/test-MainActivity: –onResumeFragments
E/test-MainActivity: –onPostResume
结论:当所依赖的MainActivity切换到前台,Fragment同样会执行对应的生命周期方法:onStart–onResume
结论:
1.6 大总结:在初始化和前后台切换的过程中Fragment和MainActivity对应生命周期的回调是一致的,
特殊点在于Fragment之间来回切换并不会回调Fragment和MainActivity的任何生命周期方法,但是会
回调onHiddenChanged方法,并且初始化过程中只有add之后再调用hide的时候从显示变成了隐藏才会
回调onHiddenChanged方法,这样如果我们想要在摸个Fragment显示的时候做一些和onResume方法中同
样的数据初始化工作就不会发生重复和冲突,所以我们可以在Fragment显示的时候在onHiddenChanged的

hidden=false的时候做onResume中同样的初始化工作。(由此可见Google大佬们的设计之精妙)

用这种方法就能实现Fragment切换的最佳实践:切换显示状态的时候并不会销毁或者重新创建,而是
每个Fragment都始终加载完成并保存在内存中,并且在任何时候进行显示状态的切换都有回调可以做。
实际需求分析,数据初始化工作(initData();):
第一大类:大部分非新闻类客户端几个主要页面都不是需要加载大量数据的,除了个别参数需要请求初始化,这种项目实际开发中主页面切换基本分为两大情况:
1.只需要页面初始化时候初始化数据,之后切换过程中不会变化:
这种情况我们只需要在fragment的onCreateView或者onActivityCreated中做初始化数据操作(调用initData方法)。
2.每次页面可见都要刷新的数据,包括:初始化创建、前后台切换(从其他页面跳转回来属于前后台切换的一种情况)和叶签切换:
结合上面对生命周期的分析结果,这种需求下我们可以通过在onResume方法中调用initData方法完成初始化创建和前后台切换这两种情况下的数据刷新;而通过在
onHiddenChanged中调用initData方法完成叶签切换这种情况下的数据刷新,这样就保证了只要页面可见都会刷新数据。
第二大类:就是类似新闻客户端和app下载市场类的客户端,这种客户端除了“更多”页面不需要加载大量数据,其它页面都需要加载大量的即时信息,但由于这里说的是主布局,主布局中导航叶签不可能过多,所以这里就不讨论叶签过多时候的对象销毁问题(参考:http://blog.csdn.net/u013168615/article/details/51463508),只考虑大数据量的问题:
布局预加载是有好处了,主要是防止数据预加载:
1.如果是tab+fragment方式实现UI,就用onHiddenChanged方法防止数据预加载
2.如果是用viewpager+fragment方式实现UI,就用在fragment基类中重写setUserVisibleHint方法防止数据预加载(同样参考另一篇博客:http://blog.csdn.net/u013168615/article/details/51463508)

2.通过replace方法控制Fragment的隐藏和显示的切换
2.1——————————————-初始化,初始显示IndexFragment:
E/test-MainActivity: –onCreate
/com.testfragmentlifecircle E/test-IndexFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-IndexFragment: –onCreate
/com.testfragmentlifecircle E/test-IndexFragment: –onCreateView
/com.testfragmentlifecircle E/test-IndexFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
E/test-MainActivity: –onStart
E/test-MainActivity: –onResume
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
E/test-MainActivity: –onResumeFragments
E/test-MainActivity: –onPostResume
结论:
结论:
2.2——————————————-从IndexFragment切换到MineFragment:(直接replace)
/com.testfragmentlifecircle E/test-IndexFragment: –onPause
/com.testfragmentlifecircle E/test-IndexFragment: –onStop
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroyView
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroy
/com.testfragmentlifecircle E/test-IndexFragment: –onDetach
/com.testfragmentlifecircle E/test-MineFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-MineFragment: –onCreate
/com.testfragmentlifecircle E/test-MineFragment: –onCreateView
/com.testfragmentlifecircle E/test-MineFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-MineFragment: –onStart
/com.testfragmentlifecircle E/test-MineFragment: –onResume
———————————————-再切换回IndexFragment
/com.testfragmentlifecircle E/test-MineFragment: –onPause
/com.testfragmentlifecircle E/test-MineFragment: –onStop
/com.testfragmentlifecircle E/test-MineFragment: –onDestroyView
/com.testfragmentlifecircle E/test-MineFragment: –onDestroy
/com.testfragmentlifecircle E/test-MineFragment: –onDetach
/com.testfragmentlifecircle E/test-IndexFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-IndexFragment: –onCreate
/com.testfragmentlifecircle E/test-IndexFragment: –onCreateView
/com.testfragmentlifecircle E/test-IndexFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
结论:replace内部实现,就是remove掉之前所添加(add)过的所有Fragment,然后再添加并显示当前Fragment,
所以之前的Fragment的对象会被彻底销毁。
结论:
2.3——————————————-从IndexFragment切换到MineFragment:(给FragmentTransaction设置addToBackStack(null)之后再replace)
/com.testfragmentlifecircle E/test-IndexFragment: –onPause
/com.testfragmentlifecircle E/test-IndexFragment: –onStop
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroyView
/com.testfragmentlifecircle E/test-MineFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-MineFragment: –onCreate
/com.testfragmentlifecircle E/test-MineFragment: –onCreateView
/com.testfragmentlifecircle E/test-MineFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-MineFragment: –onStart
/com.testfragmentlifecircle E/test-MineFragment: –onResume
———————————————-再切换回IndexFragment
/com.testfragmentlifecircle E/test-MineFragment: –onPause
/com.testfragmentlifecircle E/test-MineFragment: –onStop
/com.testfragmentlifecircle E/test-MineFragment: –onDestroyView
/com.testfragmentlifecircle E/test-IndexFragment: –onCreateView
/com.testfragmentlifecircle E/test-IndexFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
结论:这种实现方式即没有彻底销毁Fragment对象,还能在Fragment切换的时候正常回调onResume方法,比较接近最佳实践,
但是只是没有彻底销毁Fragment对象,而是把对象存储到内存中,但是Fragment中的视图仍需要重新构建。
我们通常复写Fragment就是从onCreateView方法开始,等于说对我们而言这些页面初始化工作每次显示都需要重来,只是framework层
不需要彻底销毁Fragment对象而已,所以这种方式可以解决生命周期一致性问题,因为同一时间只会走被替换掉fragment的布局销毁流程和当前fragment的布局创建流程,但是fragment的布局预加载对于性能是有好处的,只是要防止数据重新加载而已。
结论:
优点:这种方法可以避免数据预加载,可以保证生命周期一致性
缺点:需要在每次fragment切换出来的时候重建布局,这在实际开发中会导致布局和数据的重新初始化;并且fragment的对象始终存在于内存中,这对于fragment数据较多的情况显然是不可以接受的,对于需要频繁切换的主页面也是不可以接受的。

3.通过dettach和attach方法控制Fragment的隐藏和显示的切换
3.1——————————————-初始化,初始显示IndexFragment:
E/test-MainActivity: –onCreate
/com.testfragmentlifecircle E/test-IndexFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-IndexFragment: –onCreate
/com.testfragmentlifecircle E/test-MineFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-MineFragment: –onCreate
/com.testfragmentlifecircle E/test-MoreFragment: –onAttach
E/test-MainActivity: –onAttachFragment
/com.testfragmentlifecircle E/test-MoreFragment: –onCreate
/com.testfragmentlifecircle E/test-IndexFragment: –onCreateView
/com.testfragmentlifecircle E/test-IndexFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
E/test-MainActivity: –onStart
E/test-MainActivity: –onResume
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
E/test-MainActivity: –onResumeFragments
E/test-MainActivity: –onPostResume
结论:只有初始化和MainActivity想关联(attach)的Fragment才会走完显示的生命周期,而初始化和MainActivity
不关联(dettach)的Fragment只回调onAttach和onCreate就完了,这说明不关联的Fragment已经创建好并且存储在
内存中
结论:
3.2——————————————-退出应用,即退出MainActivity:
E/test-MainActivity: –onBackPressed
/com.testfragmentlifecircle E/test-IndexFragment: –onPause
E/test-MainActivity: –onPause
/com.testfragmentlifecircle E/test-IndexFragment: –onStop
E/test-MainActivity: –onStop
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroyView
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroy
/com.testfragmentlifecircle E/test-IndexFragment: –onDetach
/com.testfragmentlifecircle E/test-MineFragment: –onDestroy
/com.testfragmentlifecircle E/test-MineFragment: –onDetach
/com.testfragmentlifecircle E/test-MoreFragment: –onDestroy
/com.testfragmentlifecircle E/test-MoreFragment: –onDetach
E/test-MainActivity: –onDestroy
结论:
结论:
3.3——————————————-从IndexFragment切换到MineFragment:
/com.testfragmentlifecircle E/test-IndexFragment: –onPause
/com.testfragmentlifecircle E/test-IndexFragment: –onStop
/com.testfragmentlifecircle E/test-IndexFragment: –onDestroyView
/com.testfragmentlifecircle E/test-MineFragment: –onCreateView
/com.testfragmentlifecircle E/test-MineFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-MineFragment: –onStart
/com.testfragmentlifecircle E/test-MineFragment: –onResume
———————————————-再切换回IndexFragment
/com.testfragmentlifecircle E/test-IndexFragment: –onCreateView
/com.testfragmentlifecircle E/test-IndexFragment: –onActivityCreated
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
/com.testfragmentlifecircle E/test-MineFragment: –onPause
/com.testfragmentlifecircle E/test-MineFragment: –onStop
/com.testfragmentlifecircle E/test-MineFragment: –onDestroyView
结论:由此可见attach和dettach的使用,和replace+addToBackStack(null)的使用效果是一样的:
当前没有显示的Fragment的对象并没有被彻底销毁,而是存储在回收栈中,当需要显示的时候只需要重新构建布局,
从onDestroyView开始就行了。所以对于即不要每次都重新加载有想要生命周期一致的情况,这同样不是完美的最佳实践。
结论:
3.4——————————————-从前台切换到后台:
/com.testfragmentlifecircle E/test-IndexFragment: –onPause
E/test-MainActivity: –onPause
/com.testfragmentlifecircle E/test-IndexFragment: –onSaveInstanceState
/com.testfragmentlifecircle E/test-MineFragment: –onSaveInstanceState
/com.testfragmentlifecircle E/test-MoreFragment: –onSaveInstanceState
E/test-MainActivity: –onSaveInstanceState
/com.testfragmentlifecircle E/test-IndexFragment: –onStop
E/test-MainActivity: –onStop
———————————————-再切换回前台
/com.testfragmentlifecircle E/test-IndexFragment: –onStart
E/test-MainActivity: –onStart
E/test-MainActivity: –onResume
/com.testfragmentlifecircle E/test-IndexFragment: –onResume
E/test-MainActivity: –onResumeFragments
E/test-MainActivity: –onPostResume
结论:只有当前处于关联状态的Fragment会执行和MainActivity一致的生命周期
结论:

4.总结:
Fragment管理的最佳实践一:
add、hide和show,并通过onHiddenChanged完成Fragment之间切换时候的初始化工作。
实践目标:
(1)每个Fragment显示状态切换的时候既不会销毁和重建对象,也不会销毁和重建布局
(2)通过onHiddenChanged完成Fragment之间切换完成前后台切换时候onResume里面需要做的初始化工作,弥补了生命周期不一致所带来的Fragment之间切换时候的初始化工作不能完全同步的问题

Fragment管理的实践二:replace+addToBackStack(null)
fragment的管理从操作流程上来说可以分为同级式和流程式(参考:http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650820216&idx=1&sn=64d0380fedf947c7adefc6d3eb722301&scene=23&srcid=0523Avr6W8UuVzqGIGQrLFUD#rd),上面所描述的就是典型的同级式的最佳实践方法,而流程式的实现就需要用这种方法,具体实现参考链接中描述。
实践目标:
(1)所有显示过的fragment的对象都在内存中,被替换掉的fragment是布局被销毁,而对象并没有完全被销毁
(2)被替换掉的布局重新显示时候声明周期从onCreateView–…–onResume,除了fragment对象不重新onAttach和onCreate之外,可以通过popBackStack返回上一级fragment。


总的来说:add、hide、show+onHiddenChanged这种方法,适合同级fragment的需求,3个或者3个以下,数据不多可以不考虑数据预加载,数据多的话可以取消数据预加载;
replace+addToBackStack(null)方法,适合流程式fragment管理;
viewpager+fragment:适合同级多个fragment的情况。


测试源码demo:

API不再逐个分析,参考:
http://www.pocketdigi.com/20141006/1385.html
http://blog.csdn.net/buaaroid/article/details/48265105
http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650820216&idx=1&sn=64d0380fedf947c7adefc6d3eb722301&scene=23&srcid=0523Avr6W8UuVzqGIGQrLFUD#rd

你可能感兴趣的:(Android开发)