前言
-
缓存的目的是为什么?
答:为了预加载。
-
什么是预加载?
答:Fragment切换的时候,会预先加载未可见的Fragment,就是预加载。
-
在缓存页面setOffscreenPageLimit(int limit) 是什么?
答:可以设置缓存页面,设置3就是缓存6个Fragment,设置4就是缓存8个Fragment。
-
为什么这个函数设置 0 无效,为什么缓存的页面数不能低于1?
答:setOffscreenPageLimit 看源码分析,因为就算是设置0,默认内部也会被修改成1。
-
在预加载 - setOffscreenPageLimit(int limit) 是什么?
答:可以设置预加载,设置2就是预加载T2、T3。默认打开T1,预加载T2、T3;默认打开T2,预加载T3、T4
-
预加载会带来什么问题?怎么解决?
答:会带来问题:1.预加载的越多就会越卡;2.一个Fragment占用 1M,5个就(5*1M),累计到后面就会OOM;3.如果预加载的Fragment在请求网络,不仅浪费流量,还会很卡顿.......解决办法:使用懒加载,来解决预加载带来的问题。
-
懒加载 是什么?
答:防止预加载,用到才加载,可见才加载,不可见就不加载。
懒加载,其实也就是延迟加载,就是等到该页面的UI展示给用户时,再加载该页面的数据(从网络、数据库等),而不是依靠 ViewPager预加载机制提前加载两三个,甚至更多页面的数据。
目的:这样可以提高所属Activity的初始化速度,也可以为用户节省流量。而这种懒加载的方式也已经正在被诸多APP所采用。
源码解析
ViewPager.onMeasure(int widthMeasureSpec, int heightMeasureSpec)
//这个是最重要的步骤
--> populate();
--> populate(mCurItem);
//准备适配
--> mAdapter.startUpdate(this);
--> startUpdate((View) container);
--> curItem = addNewItem(mCurItem, curIndex);
//创建适配的item数据
--> ii.object = mAdapter.instantiateItem(this, position);
--> fragment.setMenuVisibility(false);@FragmentPagerAdapter
--> fragment.setUserVisibleHint(false);
//销毁适配的item数据
--> mAdapter.destroyItem(this, pos, ii.object);
--> mCurTransaction = mFragmentManager.beginTransaction();@FragmentPagerAdapter
//设置当前显示的item数据
--> mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
--> if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
//重置上一个item的属性
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
//设置当前item的属性
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
mCurrentPrimaryItem = fragment;
}
//完成适配。接着才开始执行fragment的生命周期
--> mAdapter.finishUpdate(this);
--> mCurTransaction.commitNowAllowingStateLoss();
setOffscreenPageLimit(int limit)
//DEFAULT_OFFSCREEN_PAGES = 1,如果limit<1,则设置为1。也就解释了为什么设置0无效。
--> if (limit < DEFAULT_OFFSCREEN_PAGES) {
Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "+ DEFAULT_OFFSCREEN_PAGES);
limit = DEFAULT_OFFSCREEN_PAGES;
}
if (limit != mOffscreenPageLimit) {
mOffscreenPageLimit = limit;
//这边同样会执行populate(),具体分析同上
populate();
}
流程分析
1、初次进入:
scom.xh.myviewpagerfragmentapp D/BlankFragment: etUserVisibleHint: tab=1,isVisibleToUser=false
com.xh.myviewpagerfragmentapp D/BlankFragment: setUserVisibleHint: tab=2,isVisibleToUser=false
com.xh.myviewpagerfragmentapp D/BlankFragment: setUserVisibleHint: tab=1,isVisibleToUser=true
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=2
2、从tab1点击进入tab3:
//下面两个是由mAdapter.instantiateItem(this, position)函数触发;
setUserVisibleHint: tab=3,isVisibleToUser=false //加载tab3
setUserVisibleHint: tab=4,isVisibleToUser=false //预加载tab4
//下面两个是由mAdapter.setPrimaryItem(this, mCurItem, curItem.object);函数触发;
setUserVisibleHint: tab=1,isVisibleToUser=false //重置tab1
setUserVisibleHint: tab=3,isVisibleToUser=true //显示tab3
//下面才开始执行fragment的生命周期函数,由mAdapter.finishUpdate(this)触发
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onPause: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onStop: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onDestroyView: tab=1
使用懒加载流程:
1、在setUserVisibleHint(boolean isVisibleToUser),判断参数isVisibleToUser为true时才去加载数据,false则停止加载
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (isVisibleToUser) {
startDoThings()
} else {
stopDoThings()
}
}
2、解决崩溃:由于setUserVisibleHint(boolean isVisibleToUser)在onCreateView()之前执行,有可能view还未被创建。所以需要设置一个tag,在onCreateView()中置为true。
然后在tag为true时才去加载/停止加载数据
override fun onCreateView(inflater: LayoutInflater, container:ViewGroup?,
savedInstanceState: Bundle?): View? {
...
viewCreate = true
...
}
override fun onDestroyView() {
super.onDestroyView()
...
viewCreate = false
...
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (viewCreate) {
if (isVisibleToUser) {
startDoThings()
} else {
stopDoThings()
}
}
}
3、解决第一次进入不加载:第一次进入,setUserVisibleHint(boolean isVisibleToUser)在onCreateView()之前执行,加载数据的逻辑并未执行,
所以需要我们在onCreateView()中手动执行加载逻辑,在getUserVisibleHint()为true的时候执行。
override fun onCreateView(inflater: LayoutInflater, container:ViewGroup?,savedInstanceState: Bundle?): View? {
...
viewCreate = true
if (userVisibleHint) {
userVisibleHint = true
}
...
}
总结
Fragment 生命周期按先后顺序:
onAttach -> onCreate -> onCreatedView -> onActivityCreated -> onStart -> onResume ->
onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
ViewPager + Fragment 的实现我们需要关注的几个生命周期有: onCreatedView + onResume + onPause + onDestroyView非生命周期函数:setUserVisibleHint + onHiddenChanged
网友评论