现在的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的
用这种方法就能实现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