Fragment addToBackStack时add和replace的区别
先看下activity的代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
replace("1");
//
new Handler(){
@Override
public void handleMessage(Message msg) {
replace("2");
}
}.sendEmptyMessageDelayed(0, 5000);
}
public void replace(String tag){
MyFragment fragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("tag", tag);
fragment.setArguments(bundle);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content_main, fragment)
// .replace(R.id.content_main, fragment)
.addToBackStack(null)
.commit();
}
}
下面是activity的布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</FrameLayout>
再看Fragment
public class MyFragment extends Fragment {
private String tag;
private TextView tv;
@Override
public void onAttach(Context context) {
super.onAttach(context);
Bundle arguments = getArguments();
tag = arguments.getString("tag");
Log.i("lijing", tag + " onAttach()");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("lijing", tag + " onCreate()");
}
@Override
public void onDetach() {
super.onDetach();
Log.i("lijing", tag + " onDetach()");
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragmrnt_main, null);
tv = (TextView) view.findViewById(R.id.tv);
tv.setText(tag);
Log.i("lijing", tag + " onCreateView()");
return view;
}
@Override
public void onResume() {
super.onResume();
Log.i("lijing", tag + " onResume()");
}
@Override
public void onStart() {
super.onStart();
Log.i("lijing", tag + " onStart()");
}
@Override
public void onStop() {
super.onStop();
Log.i("lijing", tag + " onStop()");
}
@Override
public void onPause() {
super.onPause();
Log.i("lijing", tag + " onPause()");
}
下面是fragment的布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="wewewew"
android:textSize="50sp"/>
</FrameLayout>
这俩方法都是添加并显示Fragment,按下返回键会返回上一次出现的Fragment知道Activity没有添加Fragment时的那个状态,但是在生命周期方法被调用的情况却大有不同。
1. add
我先把加载完后log贴出来
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 1 onAttach()
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 1 onCreate()
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 1 onCreateView()
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 1 onStart()
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 1 onResume()
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 2 onAttach()
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 2 onCreate()
11-26 15:24:52.795 32217-32217/com.example.apple.fragmentdemo I/lijing: 2 onCreateView()
11-26 15:24:52.802 32217-32217/com.example.apple.fragmentdemo I/lijing: 2 onStart()
11-26 15:24:52.760 32217-32217/com.example.apple.fragmentdemo I/lijing: 2 onResume()
接下来我们按下home键
11-26 11:47:44.818 28300-28300/com.example.apple.fragmentdemo I/lijing: 1 onPause()
11-26 11:47:44.818 28300-28300/com.example.apple.fragmentdemo I/lijing: 2 onPause()
11-26 11:47:44.834 28300-28300/com.example.apple.fragmentdemo I/lijing: 1 onStop()
11-26 11:47:44.818 28300-28300/com.example.apple.fragmentdemo I/lijing: 2 onStop()
这时我们会发现两个Fragment都走了 onPause和onStop方法,
如果按返回键
11-26 11:50:57.443 28248-28248/com.example.apple.fragmentdemo I/lijing: 2 onPause()
11-26 11:50:57.444 28248-28248/com.example.apple.fragmentdemo I/lijing: 2 onStop()
11-26 11:50:57.449 28248-28248/com.example.apple.fragmentdemo I/lijing: 2 onDetach()
此时fragment1处于显示状态,但是并没有掉任何生命周期的方法,说明fragment1的状态没有发生任何变化。
add这种方式极像往Framelayout里面添加View,把上面的View remove,就露出了下面的View。
2. replace
我把添加fragment的方式改为replace,当初始完成的时候,生命周期方法调用顺序为
11-26 15:23:28.707 31466-31466/com.example.apple.fragmentdemo I/lijing: 1 onAttach()
11-26 15:23:28.707 31466-31466/com.example.apple.fragmentdemo I/lijing: 1 onCreate()
11-26 15:23:28.713 31466-31466/com.example.apple.fragmentdemo I/lijing: 1 onCreateView()
11-26 15:23:28.707 31466-31466/com.example.apple.fragmentdemo I/lijing: 1 onStart()
11-26 15:23:28.717 31466-31466/com.example.apple.fragmentdemo I/lijing: 1 onResume()
11-26 15:23:33.710 31466-31466/com.example.apple.fragmentdemo I/lijing: 2 onAttach()
11-26 15:23:28.707 31466-31466/com.example.apple.fragmentdemo I/lijing: 2 onCreate()
11-26 15:23:33.712 31466-31466/com.example.apple.fragmentdemo I/lijing: 1 onPause()
11-26 15:23:33.713 31466-31466/com.example.apple.fragmentdemo I/lijing: 1 onStop()
11-26 18:26:49.882 20382-20382/com.example.apple.fragmentdemo I/lijing: 1 onDestroyView()
11-26 15:23:33.755 31466-31466/com.example.apple.fragmentdemo I/lijing: 2 onCreateView()
11-26 15:23:33.761 31466-31466/com.example.apple.fragmentdemo I/lijing: 2 onStart()
11-26 15:23:33.762 31466-31466/com.example.apple.fragmentdemo I/lijing: 2 onResume()
我很疑惑,为什么activity没有进入pause状态,而fragment1的onPause方法会被回调?
通过打断点我看到了方法的调用栈:
BackStackRecord 继承自FragmentTransaction, 每次用fragmentTransaction添加显示fragment时,就会配置一个BackStackPecord的静态内部类Op,这个对象记录了所有加进来的fragment的状态,其中Op.cmd有几种状态:
这时我可以看到已经添加进来了两个Fragment:fragment1和fragment2。他们的配置信息如下:
可以清楚的看到fragment1的cmd值为3,也就是OP_REMOVE, 而fragment2的cmd值为1,也就是OP_ADD。
现在我们再回到BackStackRecord.executeOps方法,找到其中的关键代码
只要cmd的值不是OP_ADD就会执行大括号里面的方法,进去这个方法,
我们先看moveToState这个方法的调用传的餐数,关键的是第二个,mCurState这个值是一直变化的,他和当前显示的Fragment的状态保持一致,这个值有5种状态:
接下来再往里看,进入到moveToState方法,由于这个方法代码比较多,我只贴出来关键的
为什么能执行到这里我只是猜测:
f.mState > newState: 这个newState就是FragmentManager的mCurState,此时,刚刚把fragment2添加进来,这个时候fragment2还没有显示,所以newState的值为1(CREATED);
接下来就得到了我们问题的答案,f.performePause().
我们言归主题,fragment2以replace方式添加显示的时候,先要把当前显示的fragment1隐藏起来,调用fragment1的onPause 和 onStop 方法,但是并没有把fragment1完全的清除,我们看到,并没有掉用fragment1的onDetach方法。只是隐藏。从下面的log里面可以进一步验证。
当这个时候按下home键时:
11-26 15:31:24.292 706-706/com.example.apple.fragmentdemo I/lijing: 1 onPause()
11-26 15:31:24.292 706-706/com.example.apple.fragmentdemo I/lijing: 2 onPause()
11-26 15:31:24.308 706-706/com.example.apple.fragmentdemo I/lijing: 1 onStop()
11-26 15:31:24.308 706-706/com.example.apple.fragmentdemo I/lijing: 2 onStop()
这时很好理解,既然没有被清楚,肯定会跟随Activity的生命周期,执行onPause,onStart方法。
如果我们按下返回键:
11-26 18:23:53.837 19261-19261/com.example.apple.fragmentdemo I/lijing: 2 onPause()
11-26 18:23:53.837 19261-19261/com.example.apple.fragmentdemo I/lijing: 2 onStop()
11-26 18:23:53.841 19261-19261/com.example.apple.fragmentdemo I/lijing: 2 onDetach()
11-26 18:23:53.863 19261-19261/com.example.apple.fragmentdemo I/lijing: 1 onCreateView()
11-26 18:23:53.870 19261-19261/com.example.apple.fragmentdemo I/lijing: 1 onStart()
11-26 18:23:53.837 19261-19261/com.example.apple.fragmentdemo I/lijing: 1 onResume()
着很清楚了,fragment1有重新创建View,走了onCreateView方法,