一般操作一个fragment是使用fragmentTransaction,fragmentTransaction由fragmentManager获取。
manager = getSupportFragmentManager();
FragmentTransaction
transaction = manager.beginTransaction();
实际上manager是个FragmentManagerImpl对象,而beginTransaction返回的是一个BackStackRecord具体对象
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
FragmentTransaction有多个方法,add,remove,replace(实际上是remove和add的结合),hide,show,detach,attach,addToBackStack。。。
最后都会调用commit来完成一系列动作的提交。
transaction.add()会执行生命周期:
06-29 18:43:47.332 9099-9099/com.txt.mydemo I/OneFragment: onAttach
06-29 18:43:47.332 9099-9099/com.txt.mydemo I/OneFragment: onCreate
06-29 18:43:47.332 9099-9099/com.txt.mydemo I/OneFragment: onCreateView
06-29 18:43:47.340 9099-9099/com.txt.mydemo I/OneFragment: onViewCreated
06-29 18:43:47.340 9099-9099/com.txt.mydemo I/OneFragment: onActivityCreated
06-29 18:43:47.340 9099-9099/com.txt.mydemo I/OneFragment: onStart
06-29 18:43:47.340 9099-9099/com.txt.mydemo I/OneFragment: onResume
transaction.remove会执行生命周期:
06-29 18:45:30.699 9099-9099/com.txt.mydemo I/OneFragment: onPause
06-29 18:45:30.699 9099-9099/com.txt.mydemo I/OneFragment: onStop
06-29 18:45:30.699 9099-9099/com.txt.mydemo I/OneFragment: onDestroyView
06-29 18:45:30.942 9099-9099/com.txt.mydemo I/OneFragment: onDestroy
06-29 18:45:30.942 9099-9099/com.txt.mydemo I/OneFragment: onDetach
而使用hide、show则不会执行生命周期,其实就类似于view的setvisible设置可见性
如下这个示例:
public class FragmentActivity extends AppCompatActivity implements OneFragment.OnFragmentInteractionListener{
private FragmentManager manager;
private static final String TAG1 = "TAG1", TAG2 = "TAG2";
// private FragmentTransaction transaction;//只能作为局部变量,一次只能执行一个fragment的commit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_test);
manager = getSupportFragmentManager();
}
public void tab1(View view){
Fragment fragment = manager.findFragmentByTag(TAG1);
FragmentTransaction
transaction = manager.beginTransaction();
//设置动画效果,必须在add ,replace,remove之前调用
//使用系统默认的动画
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
//使用自定义的动画
transaction.setCustomAnimations(R.anim.slide_in_from_right,R.anim.slide_in_from_right);
if(manager.findFragmentByTag(TAG2) != null){
transaction.hide(manager.findFragmentByTag(TAG2));
}
if( fragment != null ){
transaction.show(fragment);
}else {
transaction.add(R.id.content, OneFragment.newInstance("1", "2"), TAG1);
// transaction.addToBackStack(null);//添加到回退栈中,在这里只是记录一个标记,其实是在commit中,调用fragmentManager的allocBackStackIndex方法,所以回退栈是由fragmentManager管理的。必须在commit之前
}
transaction.commit();
}
public void tab2(View view){
Fragment fragment = manager.findFragmentByTag(TAG2);
FragmentTransaction transaction = manager.beginTransaction();
if (manager.findFragmentByTag(TAG1) != null) {
transaction.hide(manager.findFragmentByTag(TAG1));
}
if( fragment != null ) {
transaction.show(fragment);
}else {
transaction.add(R.id.content, TwoFragment.newInstance("abc"), TAG2);
// transaction.addToBackStack(null);
}
transaction.commit();
}
//activity向fragment传值
private void setTextToFragment(){
((OneFragment)manager.findFragmentByTag("tab1")).setTextByActivity();
}
//实现tab1的回调接口(即fragment向activity传值)
@Override
public void onFragmentInteraction(Uri uri) {
}
}
使用hide和show来切换连个fragment,并且添加fragment的时候不加入回退栈,那么在activity中按back键的时候,两个fragment的生命周期是这样的:
06-29 18:55:34.996 25403-25403/com.txt.mydemo I/OneFragment: onPause
06-29 18:55:34.996 25403-25403/com.txt.mydemo I/TwoFragment: onPause
06-29 18:55:35.106 25403-25403/com.txt.mydemo W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (2560x1440, max=2048x2048)
06-29 18:55:35.496 25403-25403/com.txt.mydemo I/OneFragment: onStop
06-29 18:55:35.496 25403-25403/com.txt.mydemo I/TwoFragment: onStop
06-29 18:55:35.496 25403-25403/com.txt.mydemo I/OneFragment: onDestroyView
06-29 18:55:35.504 25403-25403/com.txt.mydemo I/OneFragment: onDestroy
06-29 18:55:35.504 25403-25403/com.txt.mydemo I/OneFragment: onDetach
06-29 18:55:35.504 25403-25403/com.txt.mydemo I/TwoFragment: onDestroyView
06-29 18:55:35.504 25403-25403/com.txt.mydemo I/TwoFragment: onDestroy
06-29 18:55:35.504 25403-25403/com.txt.mydemo I/TwoFragment: onDetach
一起结束。
把addToBackStack的注释去掉,则根据添加的先后顺序,依次销毁fragment,不管中间切换过几次hide或show
比如先添加tab2,在添加tab1,back键销毁的是这样的:
06-29 19:07:22.567 30394-30394/com.txt.mydemo I/OneFragment: onPause
06-29 19:07:22.567 30394-30394/com.txt.mydemo I/OneFragment: onStop
06-29 19:07:22.567 30394-30394/com.txt.mydemo I/OneFragment: onDestroyView
06-29 19:07:22.824 30394-30394/com.txt.mydemo I/OneFragment: onDestroy
06-29 19:07:22.824 30394-30394/com.txt.mydemo I/OneFragment: onDetach
--------- beginning of /dev/log/system
06-29 19:07:24.824 30394-30394/com.txt.mydemo I/TwoFragment: onPause
06-29 19:07:24.824 30394-30394/com.txt.mydemo I/TwoFragment: onStop
06-29 19:07:24.824 30394-30394/com.txt.mydemo I/TwoFragment: onDestroyView
06-29 19:07:24.824 30394-30394/com.txt.mydemo I/TwoFragment: onDestroy
06-29 19:07:24.832 30394-30394/com.txt.mydemo I/TwoFragment: onDetach
先销毁了后加入的oneFragment。
接着看下replace时的生命周期,先点击tab1按钮,添加oneFragment到界面上,然后点击replaceTab1按钮,添加twoFragment到界面上。在操作这两步的时候,把addTOBackStack方法注释掉,看下效果:
增加了replaceTab1方法
public class FragmentActivity extends AppCompatActivity implements OneFragment.OnFragmentInteractionListener{
private FragmentManager manager;
private static final String TAG1 = "TAG1", TAG2 = "TAG2";
// private FragmentTransaction transaction;//只能作为局部变量,一次只能执行一个fragment的commit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_test);
manager = getSupportFragmentManager();
}
public void tab1(View view){
// Fragment fragment = manager.findFragmentByTag(TAG1);
FragmentTransaction
transaction = manager.beginTransaction();
//设置动画效果,必须在add ,replace,remove之前调用
//使用系统默认的动画
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
//使用自定义的动画
transaction.setCustomAnimations(R.anim.slide_in_from_right,R.anim.slide_in_from_right);
// if(manager.findFragmentByTag(TAG2) != null){
// transaction.hide(manager.findFragmentByTag(TAG2));
// }
// if( fragment != null ){
// transaction.show(fragment);
// }else {
transaction.add(R.id.content, OneFragment.newInstance("1", "2"), TAG1);
// transaction.addToBackStack(null);//添加到回退栈中,在这里只是记录一个标记,其实是在commit中,调用fragmentManager的allocBackStackIndex方法,所以回退栈是由fragmentManager管理的。必须在commit之前
// }
transaction.commit();
}
public void tab2(View view){
Fragment fragment = manager.findFragmentByTag(TAG2);
FragmentTransaction transaction = manager.beginTransaction();
if (manager.findFragmentByTag(TAG1) != null) {
transaction.hide(manager.findFragmentByTag(TAG1));
}
if( fragment != null ) {
transaction.show(fragment);
}else {
transaction.add(R.id.content, TwoFragment.newInstance("abc"), TAG2);
transaction.addToBackStack(null);
}
transaction.commit();
}
public void replaceTab1(View view){
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.content, TwoFragment.newInstance("abc"), TAG2);
// transaction.addToBackStack(null);
transaction.commit();
}
//activity向fragment传值
private void setTextToFragment(){
((OneFragment)manager.findFragmentByTag("tab1")).setTextByActivity();
}
//实现tab1的回调接口(即fragment向activity传值)
@Override
public void onFragmentInteraction(Uri uri) {
}
}
1、把addToBackStack都注释掉
添加onefragment
06-29 19:38:59.629 30449-30449/com.txt.mydemo I/OneFragment: onAttach
06-29 19:38:59.629 30449-30449/com.txt.mydemo I/OneFragment: onCreate
06-29 19:38:59.629 30449-30449/com.txt.mydemo I/OneFragment: onCreateView
06-29 19:38:59.645 30449-30449/com.txt.mydemo I/OneFragment: onViewCreated
06-29 19:38:59.645 30449-30449/com.txt.mydemo I/OneFragment: onActivityCreated
06-29 19:38:59.645 30449-30449/com.txt.mydemo I/OneFragment: onStart
06-29 19:38:59.645 30449-30449/com.txt.mydemo I/OneFragment: onResume
使用replace把twofragment添加上去,很明显,没有把任何fragment加入回退栈,那么很明显,onefragment此时要被销毁了。
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/OneFragment: onPause
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/OneFragment: onStop
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/OneFragment: onDestroyView
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/OneFragment: onDestroy
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/OneFragment: onDetach
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/TwoFragment: onAttach
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/TwoFragment: onCreate
06-29 19:39:48.488 30449-30449/com.txt.mydemo I/TwoFragment: onCreateView
06-29 19:39:48.504 30449-30449/com.txt.mydemo I/TwoFragment: onViewCreated
06-29 19:39:48.504 30449-30449/com.txt.mydemo I/TwoFragment: onActivityCreated
06-29 19:39:48.504 30449-30449/com.txt.mydemo I/TwoFragment: onStart
06-29 19:39:48.504 30449-30449/com.txt.mydemo I/TwoFragment: onResume
06-29 19:40:14.559 30449-30449/com.txt.mydemo I/TwoFragment: onPause
06-29 19:40:14.676 30449-30449/com.txt.mydemo W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (2560x1440, max=2048x2048)
06-29 19:40:15.035 30449-30449/com.txt.mydemo I/TwoFragment: onStop
06-29 19:40:15.035 30449-30449/com.txt.mydemo I/TwoFragment: onDestroyView
06-29 19:40:15.035 30449-30449/com.txt.mydemo I/TwoFragment: onDestroy
06-29 19:40:15.035 30449-30449/com.txt.mydemo I/TwoFragment: onDetach
06-29 19:49:31.160 5569-5569/com.txt.mydemo I/OneFragment: onAttach
06-29 19:49:31.160 5569-5569/com.txt.mydemo I/OneFragment: onCreate
06-29 19:49:31.160 5569-5569/com.txt.mydemo I/OneFragment: onCreateView
06-29 19:49:31.176 5569-5569/com.txt.mydemo I/OneFragment: onViewCreated
06-29 19:49:31.176 5569-5569/com.txt.mydemo I/OneFragment: onActivityCreated
06-29 19:49:31.176 5569-5569/com.txt.mydemo I/OneFragment: onStart
06-29 19:49:31.176 5569-5569/com.txt.mydemo I/OneFragment: onResume
06-29 19:49:57.863 5569-5569/com.txt.mydemo I/OneFragment: onPause
06-29 19:49:57.863 5569-5569/com.txt.mydemo I/OneFragment: onStop
06-29 19:49:57.863 5569-5569/com.txt.mydemo I/OneFragment: onDestroyView
06-29 19:49:57.863 5569-5569/com.txt.mydemo I/TwoFragment: onAttach
06-29 19:49:57.863 5569-5569/com.txt.mydemo I/TwoFragment: onCreate
06-29 19:49:57.863 5569-5569/com.txt.mydemo I/TwoFragment: onCreateView
06-29 19:49:57.879 5569-5569/com.txt.mydemo I/TwoFragment: onViewCreated
06-29 19:49:57.879 5569-5569/com.txt.mydemo I/TwoFragment: onActivityCreated
06-29 19:49:57.879 5569-5569/com.txt.mydemo I/TwoFragment: onStart
06-29 19:49:57.879 5569-5569/com.txt.mydemo I/TwoFragment: onResume
06-29 19:50:35.942 5569-5569/com.txt.mydemo I/OneFragment: onDestroy
06-29 19:50:35.942 5569-5569/com.txt.mydemo I/OneFragment: onDetach
06-29 20:05:45.520 18607-18607/com.txt.mydemo I/OneFragment: onAttach
06-29 20:05:45.520 18607-18607/com.txt.mydemo I/OneFragment: onCreate
06-29 20:05:45.527 18607-18607/com.txt.mydemo I/OneFragment: onCreateView
06-29 20:05:45.535 18607-18607/com.txt.mydemo I/OneFragment: onViewCreated
06-29 20:05:45.535 18607-18607/com.txt.mydemo I/OneFragment: onActivityCreated
06-29 20:05:45.535 18607-18607/com.txt.mydemo I/OneFragment: onStart
06-29 20:05:45.535 18607-18607/com.txt.mydemo I/OneFragment: onResume
06-29 20:06:15.512 18607-18607/com.txt.mydemo I/OneFragment: onPause
06-29 20:06:15.512 18607-18607/com.txt.mydemo I/OneFragment: onStop
06-29 20:06:15.512 18607-18607/com.txt.mydemo I/OneFragment: onDestroyView
06-29 20:06:15.512 18607-18607/com.txt.mydemo I/TwoFragment: onAttach
06-29 20:06:15.512 18607-18607/com.txt.mydemo I/TwoFragment: onCreate
06-29 20:06:15.512 18607-18607/com.txt.mydemo I/TwoFragment: onCreateView
06-29 20:06:15.527 18607-18607/com.txt.mydemo I/TwoFragment: onViewCreated
06-29 20:06:15.527 18607-18607/com.txt.mydemo I/TwoFragment: onActivityCreated
06-29 20:06:15.527 18607-18607/com.txt.mydemo I/TwoFragment: onStart
06-29 20:06:15.527 18607-18607/com.txt.mydemo I/TwoFragment: onResume
06-29 20:07:34.090 18607-18607/com.txt.mydemo I/TwoFragment: onPause
06-29 20:07:34.090 18607-18607/com.txt.mydemo I/TwoFragment: onStop
06-29 20:07:34.090 18607-18607/com.txt.mydemo I/TwoFragment: onDestroyView
06-29 20:07:34.090 18607-18607/com.txt.mydemo I/TwoFragment: onDestroy
06-29 20:07:34.090 18607-18607/com.txt.mydemo I/TwoFragment: onDetach
06-29 20:07:34.090 18607-18607/com.txt.mydemo I/OneFragment: onCreateView
06-29 20:07:34.098 18607-18607/com.txt.mydemo I/OneFragment: onViewCreated
06-29 20:07:34.098 18607-18607/com.txt.mydemo I/OneFragment: onActivityCreated
06-29 20:07:34.098 18607-18607/com.txt.mydemo I/OneFragment: onStart
06-29 20:07:34.098 18607-18607/com.txt.mydemo I/OneFragment: onResume
06-29 20:08:57.488 18607-18607/com.txt.mydemo I/OneFragment: onPause
06-29 20:08:57.598 18607-18607/com.txt.mydemo W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (2560x1440, max=2048x2048)
06-29 20:08:58.027 18607-18607/com.txt.mydemo I/OneFragment: onStop
06-29 20:08:58.027 18607-18607/com.txt.mydemo I/OneFragment: onDestroyView
06-29 20:08:58.035 18607-18607/com.txt.mydemo I/OneFragment: onDestroy
06-29 20:08:58.035 18607-18607/com.txt.mydemo I/OneFragment: onDetach
4、再来看下,把tab1方法中的addToBackStack加上,也就是把oneFragment也加入回退栈中
06-29 20:17:58.027 30768-30768/com.txt.mydemo I/OneFragment: onAttach
06-29 20:17:58.027 30768-30768/com.txt.mydemo I/OneFragment: onCreate
06-29 20:17:58.027 30768-30768/com.txt.mydemo I/OneFragment: onCreateView
06-29 20:17:58.035 30768-30768/com.txt.mydemo I/OneFragment: onViewCreated
06-29 20:17:58.035 30768-30768/com.txt.mydemo I/OneFragment: onActivityCreated
06-29 20:17:58.035 30768-30768/com.txt.mydemo I/OneFragment: onStart
06-29 20:17:58.035 30768-30768/com.txt.mydemo I/OneFragment: onResume
06-29 20:18:30.387 30768-30768/com.txt.mydemo I/OneFragment: onPause
06-29 20:18:30.387 30768-30768/com.txt.mydemo I/OneFragment: onStop
06-29 20:18:30.387 30768-30768/com.txt.mydemo I/OneFragment: onDestroyView
06-29 20:18:30.387 30768-30768/com.txt.mydemo I/TwoFragment: onAttach
06-29 20:18:30.387 30768-30768/com.txt.mydemo I/TwoFragment: onCreate
06-29 20:18:30.387 30768-30768/com.txt.mydemo I/TwoFragment: onCreateView
06-29 20:18:30.395 30768-30768/com.txt.mydemo I/TwoFragment: onViewCreated
06-29 20:18:30.395 30768-30768/com.txt.mydemo I/TwoFragment: onActivityCreated
06-29 20:18:30.395 30768-30768/com.txt.mydemo I/TwoFragment: onStart
06-29 20:18:30.395 30768-30768/com.txt.mydemo I/TwoFragment: onResume
06-29 20:20:07.746 30768-30768/com.txt.mydemo I/TwoFragment: onPause
06-29 20:20:07.746 30768-30768/com.txt.mydemo I/TwoFragment: onStop
06-29 20:20:07.746 30768-30768/com.txt.mydemo I/TwoFragment: onDestroyView
06-29 20:20:07.746 30768-30768/com.txt.mydemo I/TwoFragment: onDestroy
06-29 20:20:07.746 30768-30768/com.txt.mydemo I/TwoFragment: onDetach
06-29 20:20:07.746 30768-30768/com.txt.mydemo I/OneFragment: onCreateView
06-29 20:20:07.762 30768-30768/com.txt.mydemo I/OneFragment: onViewCreated
06-29 20:20:07.762 30768-30768/com.txt.mydemo I/OneFragment: onActivityCreated
06-29 20:20:07.762 30768-30768/com.txt.mydemo I/OneFragment: onStart
06-29 20:20:07.762 30768-30768/com.txt.mydemo I/OneFragment: onResume
06-29 20:26:34.926 30768-30768/com.txt.mydemo I/OneFragment: onPause
06-29 20:26:34.926 30768-30768/com.txt.mydemo I/OneFragment: onStop
06-29 20:26:34.926 30768-30768/com.txt.mydemo I/OneFragment: onDestroyView
06-29 20:26:35.176 30768-30768/com.txt.mydemo I/OneFragment: onDestroy
06-29 20:26:35.176 30768-30768/com.txt.mydemo I/OneFragment: onDetach
addToBackStack的源码分析
另外从源码中可以看出,addToBackStack方法只是为当前的fragmentTransaction设置了一个标记,真正执行入栈的还是在调用了commit后,由fragmentManager来执行,
BackStackRecord中的设置标记mAddToBackStack为true:
public FragmentTransaction addToBackStack(String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the back stack.");
}
mAddToBackStack = true;
mName = name;
return this;
}
commit方法:
@Override
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw, null);
pw.close();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
调用了manager的allocBackStackIndex方法来入栈。
具体细节参考: 简析 addToBackStack使用和Fragment执行流程