1.getActivity() 引用问题
使用中,经常会在 Fragment 中通过 getActivity()
获取到宿主 Activity 对象,但稍有不慎便会引发下面这两个问题:
第一个, Activity 的实例销毁问题。比如,Fragment 中存在类似网络请求之类的异步耗时任务,当该任务执行完毕回调 Fragment 的方法并用到宿主 Activity 对象时,很有可能宿主 Activity 对象已经销毁,从而引发 NullPointException
等异常,甚至造成程序崩溃。
所以,异步回调时需要注意添加空值等判断(譬如:fragment.isAdd()
,getActivity()!=null
等),或者在 Fragment 创建实例时就通过 getActivity().getApplicationContext()
方法保存整个应用的上下文对象,再来使用;
第二个,内存泄漏问题。如果 Fragment 持有宿主 Activity 的引用,会导致宿主 Activity 无法回收,造成内存泄漏。所以,如果可以的话,尽量不要在 Fragment 中持有宿主 Activity 的引用。
为了解决 Context 上下文引用的问题,Fragment 提供了一个 onAttach(context)
方法,在此方法中我们可以获取到 Context 对象,如下
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
2.onActivityResult(int requestCode, int resultCode, Intent intent)
requestCode:请求码(指出该方法是从哪个请求的结果触发的)
resultCode:Activity返回的结果码(指出返回的数据来自于哪个新的Activity)
Fragment 类提供有 startActivityForResult()
方法用于 Activity 间的页面跳转和数据回传,其实内部也是调用 Activity 的对应方法。但是在页面返回时需要注意 Fragment 没有提供 setResult()
方法(设置返回处理结果),可以通过宿主 Activity 实现。
举个例子,在 ActivityA 中的 FragmentA 里面调用 startActivityForResult()
跳转至 ActivityB 中,并在 ActivityB 中的 FragmentB 里面返回到 ActivityA
// FragmentA 中页面跳转和数据回传
...
Intent intent = new Intent(getContext(), ActivityB.class);
getActivity().startActivityForResult(intent, 0);
// FragmentB 里面返回到 ActivityA
Intent intent = new Intent(getActivity(), ActivityA.class);
intent.putExtra("test", test);
getActivity().setResult(0, intent);
getActivity().finish();
在回调时,先会回调 ActivityA 中的 onActivityResult() 方法,然后再分发回调 FragmentA 中的 onActivityResult() 方法。
// 回调 ActivityA 中的 onActivityResult() 方法
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// 处理特定的结果
if (requestCode == 0 && resultCode == 0) {
// 取出Intent里的Extras数据
Bundle data = intent.getExtras();
// 取出Bundle中的数据
String result = data.getString("test");
Toast.makeText(getApplicationContext(), result, 0).show();
}
}
}
...
// 回调 FragmentA 中的 onActivityResult() 方法
...
3.getChildFragmentManager()
Activity:getFragmentManager()
在 Activity 嵌入 Fragment 时,需要使用 FragmentManager,通过 Activity 提供的 getSupportFragmentManager()
方法即可获取,用于管理 Activity 里面嵌入的所有一级 Fragment。
Fragment:getChildFragmentManager()
但是对于继续嵌套二级甚至三级 Fragment,即 Activity 嵌套多级 Fragment。此时在 Fragment 里管理子 Fragment 时,也需要使用到 FragmentManager。但是一定要使用 getChildFragmentManager()
方法获取 FragmentManager 对象。
4.Fragment + ViewPager
ViewPager 提供了两种页面适配器来管理不同 Fragment 之间的滑动切换:FragmentPagerAdapter
和 FragmentStatePagerAdapter
。
使用 FragmentPagerAdapter 时,ViewPager 中的所有 Fragment 实例常驻内存,当 Fragment 变得不可见时仅仅是视图结构的销毁,即调用了 onDestroyView() 方法。由于 FragmentPagerAdapter 内存消耗较大,所以适合少量静态页面的场景。
使用 FragmentStatePagerAdapter 时,当 Fragment 变得不可见,不仅视图层次销毁,实例也被销毁,即调用了 onDestroyView() 和 onDestroy() 方法,仅仅保存 Fragment 状态。相比而言, FragmentStatePagerAdapter 内存占用较小,所以适合大量动态页面,比如我们常见的新闻列表类应用。