正常在Activity中使用Fragment的生命周期,第一次启动过程是onAtach()-onCreate()-onCreateView()-onViewCreated()-onActivityCreated()-onStart()-onResume();随着Activity被退栈销毁,Fragment的声明周期依次为onPause()-onStop()-onDestroyView()-onDestroy()-onDetach();
如果在Fragment中使用EventBus等通过反射进行的操作,在Fragment执行完onCreate()之后就会直接调用反射相关方法,由于还没有走onCreateView()等方法创建视图,所以在反射相关方法中如果直接做UI层更新就会出现空指针异常等情况。这个Bug引导我开始关注FragmentManager的原理。
下面是Bug的使用场景:在一个Activity中创建AFragment和BFragment和一个相对应的两个Button,在点击AButton时显示AFragment,点击BButton是显示BFragment,同时在BFragment中执行相应操作后,使用EventBus发送一个event,之后在Activity和AFragment中分别接收这个event,并执行相应操作使得界面显示到AFragment并对AFragment中的数据进行更新。由于Activity中使用FragmentManager对两个Fragment进行切换,所以在AFragment接收event时有各种问题。原始未修复代码如下:
1 SecondActivity.class
2 @Override
3 protected void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 EventBus.getDefault().register(this);
6 setContentView(R.layout.activity_second);
7 but1= (Button) findViewById(R.id.but1);
8 but2= (Button) findViewById(R.id.but2);
9 but1.setOnClickListener(this);
10 but2.setOnClickListener(this);
11 aFragment=AFragment.newInstance(null, null);
12 bFragment=BFragment.newInstance(null, null);
13 changeFragment(aFragment);
14 // addFragmentTransaction(aFragment);
15 // addFragmentTransaction(bFragment);
16
17 }
18
19 @Subscribe(threadMode = ThreadMode.MAIN)
20 public void handlerEvent(FragmentEvent event){
21 Log.i(TAG, "SecondActivity.onMainThread: event="+event);
22 changeFragment(aFragment);
23 }
24
25 private void changeFragment(Fragment f){
26 changeFragment1(f);
27 }
28
29 private void changeFragment1(Fragment f){
30 Log.i(TAG, "SecondActivity.changeFragment1: f="+f.getClass().getName());
31 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
32 transaction.replace(R.id.fl_container, f);
33 // transaction.addToBackStack(f.getClass().getName());
34 transaction.commit();
35 if(f.getClass().getName().equals(aFragment.getClass().getName())){
36 bFragment.setUserVisibleHint(false);
37 aFragment.setUserVisibleHint(true);
38 }else {
39 bFragment.setUserVisibleHint(true);
40 aFragment.setUserVisibleHint(false);
41 }
42 }
1 AFragment.class
2
3 private TextView titleTV;
4 @Override
5 public void onCreate(Bundle savedInstanceState) {
6 Log.i(TAG, "AFragment.onCreate: ");
7 super.onCreate(savedInstanceState);
8 if (getArguments() != null) {
9 mParam1 = getArguments().getString(ARG_PARAM1);
10 mParam2 = getArguments().getString(ARG_PARAM2);
11 }
12 EventBus.getDefault().register(this);
13 }
14
15 @Override
16 public View onCreateView(LayoutInflater inflater, ViewGroup container,
17 Bundle savedInstanceState) {
18 Log.i(TAG, "AFragment.onCreateView: ");
19 // Inflate the layout for this fragment
20 return inflater.inflate(R.layout.fragment_a, container, false);
21 }
22
23 @Override
24 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
25 Log.i(TAG, "AFragment.onViewCreated: ");
26 super.onViewCreated(view, savedInstanceState);
27 titleTV=(TextView)view.findViewById(R.id.tv_fa_title);
28 }
29
30 @Override
31 public void onDestroy() {
32 Log.i(TAG, "AFr