1、在fragment中为什么有时getActivity()会为null?
Fragment 的 getActivity() 会在 onDetach 之后释放持有的 Activity,因而返回了 null。
2、Fragment为什么有的时候会重叠,怎么产生的,又如何解决?
一般满足下面2个条件才可能会发生重叠:
- 发生了页面重启(旋转屏幕、内存不足等情况被强杀重启);
系统在页面重启前,帮我们保存了Fragment的状态,但是在重启后恢复时,视图的可见状态没帮我们保存,而Fragment默认的是show状态,所以产生了Fragment重叠现象。
- 重复replace|add Fragment 或者 使用show , hide控制Fragment。
我们会在Activity的onCreate()里或者Fragment的onCreateView()里加载根Fragment,如果在这里没有进行页面重启的判断的话,就可能导致重复加载Fragment引起重叠;
…
在使用replace加载Fragment时,页面重启后,Fragment视图都还没创建,所以mHidden没有意义,不会发生重叠现象;而在使用add加载时,视图是存在的并且叠加在一起,页面重启后 mHidden=false,所有的Fragment都会是show状态显示出来(即VISIBLE),从而造成了Fragment重叠!
3、Fragment懒加载
为什么要懒加载
如果我们没有对 Fragment 进行懒加载处理,那么我们就会无缘无故的加载一些并不可见的 Fragment , 也就会造成用户流量的无故消耗(我们会在 Fragment 相关生命周期函数中,请求网络或其他数据操作)。
这里"不可见的Fragment"是指,实际不可见但是相关可见生命周期函数(如 onResume 方法)被调用的 Fragment
如何实现懒加载
1、add+show+hide 模式下的方案
在没有添加懒加载之前,只要使用 add+show+hide 的方式控制并显示 Fragment, 那么不管 Fragment 是否嵌套,在初始化后,如果只调用了add+show,同级下的 Fragment 的相关生命周期函数都会被调用。且调用的生命周期函数如下所示:
onAttach -> onCreate -> onCreatedView -> onActivityCreated -> onStart -> onResume
Fragment 完整生命周期:onAttach -> onCreate -> onCreatedView -> onActivityCreated -> onStart -> onResume -> onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
我们要在 add+show+hide 模式下控制 Fragment 的懒加载,我们只需要做这两步:
- 我们需要在 onResume() 函数中调用 isHidden() 函数,来处理默认显示的 Fragment;
- 在 onHiddenChanged 函数中控制其他不可见的Fragment。
abstract class LazyFragment:Fragment(){
private var isLoaded = false //控制是否执行懒加载
/**
* 当前Fragment是否对用户可见
*/
private var isVisibleToUser = false
override fun onResume() {
super.onResume()
judgeLazyInit()
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
isVisibleToUser = !hidden
judgeLazyInit()
}
private fun judgeLazyInit() {
if (!isLoaded && !isHidden) {
lazyInit()
isLoaded = true
}
}
override fun onDestroyView() {
super.onDestroyView()
isLoaded = false
}
//懒加载方法
abstract fun lazyInit()
}
2、ViewPager+Fragment 模式下的方案
我们需要控制 setUserVisibleHint(boolean isVisibleToUser) 函数,该函数的声明如下所示:
public void setUserVisibleHint(boolean isVisibleToUser) {}
该函数与 onHiddenChanged() 作用非常相似,都是通过传入的参数值来判断当前 Fragment 是否对用户可见,只是 onHiddenChanged() 是在 add+show+hide 模式下使用,而 setUserVisibleHint 是在 ViewPager+Fragment 模式下使用。
如果我们想对 ViewPager 中的 Fragment 懒加载,我们需要这样处理:
abstract class LazyFragment : Fragment() {
/**
* 是否执行懒加载
*/
private var isLoaded = false
/**
* 当前Fragment是否对用户可见
*/
private var isVisibleToUser = false
/**
* 当使用ViewPager+Fragment形式会调用该方法时,setUserVisibleHint会优先Fragment生命周期函数调用,
* 所以这个时候就,会导致在setUserVisibleHint方法执行时就执行了懒加载,
* 而不是在onResume方法实际调用的时候执行懒加载。所以需要这个变量
*/
private var isCallResume = false
override fun onResume() {
super.onResume()
isCallResume = true
judgeLazyInit()
}
private fun judgeLazyInit() {
if (!isLoaded && isVisibleToUser && isCallResume) {
lazyInit()
Log.d(TAG, "lazyInit:!!!!!!!”)
isLoaded = true
}
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
isVisibleToUser = !hidden
judgeLazyInit()
}
//在Fragment销毁View的时候,重置状态
override fun onDestroyView() {
super.onDestroyView()
isLoaded = false
isVisibleToUser = false
isCallResume = false
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
this.isVisibleToUser = isVisibleToUser
judgeLazyInit()
}
abstract fun lazyInit()
}
4、Fragment的replace和add的区别?
Fragment 的容器一个 FrameLayout,add 的时候是把所有的 Fragment 一层一层的叠加到了 FrameLayout 上了,而 replace 的话首先将该容器中的其他 Fragment 去除掉然后将当前 Fragment 添加到容器中。
一个 Fragment 容器中只能添加一个 Fragment 种类,如果多次添加则会报异常,导致程序终止,而 replace 则无所谓,随便切换。
因为通过 add 的方法添加的 Fragment,每个 Fragment 只能添加一次,因此如果要想达到切换效果需要通过Fragment 的的 hide 和 show 方法结合者使用。将要显示的 show 出来,将其他 hide 起来。这个过程 Fragment 的生命周期没有变化。
通 过 replace 切 换 Fragment , 每 次 都 会 执 行 上 一 个 Fragment 的 onDestroyView , 新 Fragment 的onCreateView、onStart、onResume 方法。
5、getFragmentManager,getSupportFragmentManager,getChildFragmentManager三者之间的区别
因为fragment是3.0之后才有的api,就可以直接用getFragmentManager()这个方法来获取fragment管理器对象。但是3.0之前的版本如果也想获得fragment管理器对象怎么办呢?因此出现了getSupportFragmentManager,用于支持3.0以下的安卓系统API版本。
而getChildFragmentManager 是针对fragment嵌套fragment。
getFragmentManager()所得到的是所在fragment 的父容器的管理器(此处重点在父容器),
getChildFragmentManager()所得到的是在fragment 里面子容器的管理器(此处重点在子容器)。