Fragment生命周期速记
1、onAttach和onDetach是添加到Activity和从Activity中移除时回调的方法,所以是最先和最后执行的
2、然后开始创建Fragment,创建时的逻辑为:
- 先调用onCreate,表明开始创建Fragment了;注意,这时只是创建了Fragment,并没有开始创建其中的View
- 再调用onCreateView,表明开始真正创建Fragment中的View了,其作用等同于Activity的onCreate方法
- 再调用onViewCreated,表明Fragment中的View已经绘制完成了,其实这个方法没多大卵用
- 最后调用onActivityCreated,表明Activity中的所有内容(包括Fragment以及View)已经创建完毕,此时才标志着Activity的onCreate方法执行完毕了
3、中间的四个回调方法和Activity一样,没什么可说的
4、销毁时的逻辑为:
- 先调用onDestroyView,把Fragment的View销毁掉
- 再调用onDestroy把Fragment的自身干掉
Activity和Fragment相同方法的调用顺序
创建及显示时是由外A到内F(不然,外部的Activity还没有了,内部的Fragment咋显示呢)
隐藏及销毁时是由内F到外A(不然,外部的Activity都没有了,内部的Fragment咋整呢)
隐藏及销毁时是由内F到外A(不然,外部的Activity都没有了,内部的Fragment咋整呢)
一句话总结:当显示fragment的时候都是先执行activity的方法,当销毁fragment的时候都是先执行 fragment的方法。
Activity和Fragment生命周期流程图 543
Fragment必须是依存于Activity而存在的,因此Activity的生命周期会直接影响到Fragment的生命周期
Fragment生命周期方法简介
- onAttach(Activity) //当Fragment被【添加】到Activity时回调,注意,此时Activity的onCreate()方法已经开始执行。
- onCreate() //创建Fragment时回调,只会调用一次,在Activity的onCreate()方法之【后】执行
- onCreateView(LayoutInflater,ViewGroup,Bundle) //开始绘制Fragment的View时回调;这里不要做耗时操作【最重要的方法】
- onViewCreated//Fragment的View绘制完成时回调
- onActivityCreated(Bundle)//当Activity的onCreate方法完成时调用。当执行onActivityCreated()的时候 activity的onCreate才刚完成,而在此之前,activity的onCreate可能还没有完成,所以不能在此前进行与activity有交互的UI操作
- onStart() //和Activity一致,在Activity的onStart()方法之【后】执行
- onResume() //和Activity一致,在Activity的onResume()方法之【后】执行
- onPause() //和Activity一致,在Activity的onPause()方法之【前】执行
- onStop() //和Activity一致,在Activity的onStop()方法之【前】执行
- onDestroyView() //与onCreateView对应,销毁Fragment所包含的View时调用。
- onDestroy() //销毁Fragment时被回调,在Activity的onDestroy()方法之【前】执行,只会调用一次
- onDetach()//与onAttach相对应,Fragment从Activity中删除时会回调该方法,只会调用一次
静态Fragment的生命周期
当Fragment以静态的方式,即通过在
布局文件中以其它控件的方式设置时,它的生命周期随所在Activity的生命周期而发生变化。
当首次展示布局页面以及按BACK退出时,其完整生命周期方法调用的顺序是:
Fragment事务相关API
1、Fragment常用的三个类:
- android.app.Fragment 定义
- android.app.FragmentManager 用于在Activity中操作Fragment
- android.app.FragmentTransaction 保证一些列Fragment操作的原子性。事务
2
、FragmentManager可以做的事情:
- 使用findFragmentById(适用于在静态fragment,不常用)或findFragmentByTag(适用于动态加载的fragment,常用)获取activity中存在的fragment
- 使用 popBackStack()将fragment从后台堆栈中弹出 (模拟用户按下BACK 命令)
- 使用 addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener
- 开启一个事务 FragmentTransaction transaction = fm.benginTransatcion()
- transaction.add();往Activity中添加一个Fragment
- transaction.remove();从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁
- transaction.replace(容器,新的,Tag);使用另一个Fragment替换当前的Fragment,实际上就是remove(旧的)+add(新的)
- transaction.hide();隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
- transaction.show();显示之前隐藏的Fragment,在使用之前要判断是否为空以及是否隐藏
- detach();将【view】从UI中移除,和remove()不同,此时fragment的【状态】依然由FragmentManager维护
- attach();重建【view】视图,附加到UI上并显示
- transatcion.commit();提交一个事务,注意:commit方法一定要在Activity.onSaveInstance()之前调用。
4、几个API的区别
比如:我在FragmentA中的EditText填了一些数据,当切换到FragmentB后又切换回
FragmentA
时
- 如果希望回到A时还能看到以前数据,则适合你的就是hide和show(而不是用replace)。当然了不要使劲在那new实例,一定要先进行下非null判断
- 如果你的Activity一直存在,那么如果你希望回到A时看到的是全新的数据,则可以优先使用detach和attach,这样会只重建视图而不重建Fragment
- 而如果希望回到A时是重新创建的全新的FragmentA(不仅仅是视图),则你可以使用replace(即remove+ add),在Fragment比较多时这种方式是合理的(因为不需要的Fragment都被销毁了)
5、Fragment
回退栈
类似于Android系统为Activity维护的任务栈,如果你将Fragment添加到回退栈中,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中弹出,用户再次点击后退键时,才退出当前Activity。
replace方式显示Fragment,不添加到回退栈
但是当使用FragmentManager动态的管理Fragment并且涉及到是否addToBackStack时,其生命周期的展现就略微显得有些复杂了。下面,我们就探究一下这些问题。
1、当我们通过replace()方式展示FragA时,
它的生命周期展示方式是同在布局文件中静态设置的表现一模一样的。
getFragmentManager().beginTransaction().replace(R.id.frag_container, fragA, "AA").commit();
2、在
我们正常展示FragA且没有addToBackStack后,通过
replace方式用另一个FragmentB替换掉
FragA时
可以看到,FragA调用顺序为onPause, onStop, onDestroyView, onDestroy, onDetach。
这说明,
FragA已经被FragmentManager【完全】抛弃了
,取而代之的是FragB的完全展现。
3、如果此时按返回键的话,FragB的生命周期也将是onPause, onStop, onDestroyView, onDestroy, onDetach。
这说明,
在添加FragmentA时,如果没有调用addToBackStack的话,当FragmentManager以【replace】方式更换掉此FragmentA时,是不会保存被更换掉的FragmentA的状态的。即:被
更换掉的FragmentA会被完全销毁
。
replace方式显示Fragment,添加到回退栈
1、
我们
通过replace()方式
正常添加FragA,并addToBackStack,同样
,
它的生命周期展示方式是同在布局文件中静态设置的表现一模一样的。
2、然后我们用FragB来替换FragA
,并addToBackStack
,此时FragA和FragB的生命周期方法调用顺序是:
由此可以看出,FragA生命周期方法只是调用到了onDestroyView,而onDestroy和onDetach则没有被调用。
这说明
FragA的【View】已经被销毁了,但是FragmentManager并没有完全销毁【FragA】,FragA的状态被保存在FragmentManager里面。
3、然后再点击按钮A,使用FragA来替换当前显示的FragB,此时FragA和FragB的生命周期方法调用顺序为:
可以看到,FragB的生命方法调用顺序是跟FragB替换FragA时FragA的调用顺序一致的。
而此时FragA的调用则值得注意。此时FragA直接从onCreateView调起,也就是说只是重新创建了【视图】,而依然使用上次被替换时的Fragment状态。
4、此时(每次替换时都
addToBackStack
)按BACK返回时,界面是由
FragA-->
FragB,即销毁
FragA的
【视图】,重建
FragB的
【视图】
再
按BACK返回时,
界面由
FragB-->
FragA
,由于
回退栈中没有
FragB了
,所以这时会完全
【
销毁
FragB
】,并重建
FragA的
【视图】
再
按BACK返回时,【
Fragment
】
界面消失
,但
Activity不消失,
由于
回退栈中也没有
FragA了
,所以这时会完全
【
销毁
FragA
】
再
按BACK返回时,【
Activity】
界面才会完全退出。
show和hide方式显示Fragment
这里直接说结论了,因为太简单了。
在点击按钮A
展示
FragA
时
,FragA的调用顺序和上面完全一样。
然后在点击按钮B
展示
FragB
时
,FragA不会回调生命周期的任何方法(包括onPause、
onStop
)
然后再随你点击
按钮A或
按钮B,
FragA和
FragB也都
不会回调生命周期的任何方法(包括onPause、
onStop
)
这说明:使用show或hide显示或隐藏
Fragment时
,
Fragment
的生命周期不会发生任何变化。
这是我认为比较合理的方式,因为Fragment作为Activity的一部分,在
Activity
没有销毁时,没必要重复创建Fragment或Fragment中的View,特别是对于主界面中的Fragment,其使用频率非常高,把这些经常切换的Fragment放在内存中效率更高。
Activity 演示代码
public class MainActivity extends Activity {
private MyFrag fragA;
private MyFrag fragB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
// 如果fragA不存在才创建
if (fragA == null) fragA = MyFrag.newInstance("AA", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date()));
//通过replace方式展示FragA,且不添加到回退栈
getFragmentManager().beginTransaction().replace(R.id.frag_container, fragA, "AA").commit();
break;
case R.id.button2:
if (fragB == null) fragB = MyFrag.newInstance("BB", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date()));
//通过replace方式展示FragB,且不添加到回退栈
getFragmentManager().beginTransaction().replace(R.id.frag_container, fragB, "BB").commit();
break;
case R.id.button3:
if (fragA == null) fragA = MyFrag.newInstance("AA", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date()));
//通过replace方式展示FragA,添加到回退栈
getFragmentManager().beginTransaction().replace(R.id.frag_container, fragA, "AA").addToBackStack("AA").commit();
break;
case R.id.button4:
if (fragB == null) fragB = MyFrag.newInstance("BB", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date()));
//通过replace方式展示FragB,添加到回退栈
getFragmentManager().beginTransaction().replace(R.id.frag_container, fragB, "BB").addToBackStack("BB").commit();
break;
case R.id.button5:
if (fragA == null) {
fragA = MyFrag.newInstance("AA", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date()));
getFragmentManager().beginTransaction().add(R.id.frag_container, fragA, "AA").commit();
} else {
hideFrags();
getFragmentManager().beginTransaction().show(fragA).commit();
}
break;
case R.id.button6:
if (fragB == null) {
fragB = MyFrag.newInstance("BB", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date()));
getFragmentManager().beginTransaction().add(R.id.frag_container, fragB, "BB").commit();
} else {
hideFrags();
getFragmentManager().beginTransaction().show(fragB).commit();
}
break;
}
}
private void hideFrags() {
if (fragA != null && !fragA.isHidden()) getFragmentManager().beginTransaction().hide(fragA).commit();
if (fragB != null && !fragB.isHidden()) getFragmentManager().beginTransaction().hide(fragB).commit();
}
}
Fragment 演示代码
public class MyFrag extends Fragment {
private String TAG;
private String content;
/**构造时把传入的参数带进来,注意一定要通过Bundle及setArguments传递数据*/
public static MyFrag newInstance(String tag, String content) {
//把所有需要传递的数据都放在Bundle中
Bundle bundle = new Bundle();
bundle.putString("TAG", tag);
bundle.putString("content", content);
MyFrag contentFragment = new MyFrag();
//通过setArguments把Bundle传递过去
contentFragment.setArguments(bundle);
return contentFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if (bundle != null) {
TAG = bundle.getString("TAG");
content = bundle.getString("content");
}
Log.i(TAG, "onCreate");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i(TAG, "onCreateView");
TextView tv = new TextView(getActivity());
if (TAG.equalsIgnoreCase("AA")) tv.setBackgroundColor(0xff00ff00);
else tv.setBackgroundColor(0xff0000ff);
tv.setTextColor(0xffff0000);
tv.setText(TAG+"\n"+content);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 30);
return tv;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Log.i(TAG, "onViewCreated");
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
@Override
public void onDetach() {
Log.i(TAG, "onDetach");
super.onDetach();
}
@Override
public void onDestroyView() {
Log.i(TAG, "onDestroyView");
super.onDestroyView();
}
@Override
public void onStart() {
Log.i(TAG, "onStart");
super.onStart();
}
@Override
public void onStop() {
Log.i(TAG, "onStop");
super.onStop();
}
@Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
}
@Override
public void onPause() {
Log.i(TAG, "onPause");
super.onPause();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "onActivityCreated");
super.onActivityCreated(savedInstanceState);
}
}
附件列表