Android的ViewPager控件是我们Android App开发最常用的控件之一,本文将通过setOffscreenPageLimit增加缓存页面、setUserVisibleHint实现延迟加载、以及Adapter(FragmentPagerAdapter还是FragmentStatePagerAdapter)选择这3方面来谈谈Android ViewPager优化的一些要点。
通过setOffscreenPageLimit增加缓存页面
关于OffscreenPageLimit,Api文档里有这么一个注释
* Set the number of pages that should be retained to either side of the
* current page in the view hierarchy in an idle state. Pages beyond this
* limit will be recreated from the adapter when needed.
*
* <p>This is offered as an optimization. If you know in advance the number
* of pages you will need to support or have lazy-loading mechanisms in place
* on your pages, tweaking this setting can have benefits in perceived smoothness
* of paging animations and interaction. If you have a small number of pages (3-4)
* that you can keep active all at once, less time will be spent in layout for
* newly created view subtrees as the user pages back and forth.</p>
*
* <p>You should keep this limit low, especially if your pages have complex layouts.
* This setting defaults to 1.</p>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
OffscreenPageLimit默认值是1,它用于限制预加载或缓存页面的个数:
- 第一次载入时候,第2页的内容也会预装载;
- 滑到第2页时候,第3页的内容也会预装载;
- 滑到第3页时候,第4页的内容也会预装载,第1页被destory;
如果把OffscreenPageLimit的值改为2:
- 第一次载入时候,第2、3页的内容也会预装载;
- 滑到第2页时候,第4页的内容也会预装载;
- 滑到第3页时候,第5页的内容也会预装载;
- 滑到第4页时候,第6页的内容也会预装载,第1页被destory;
我们可以适当增加OffscreenPageLimit的值,但也不能太大,如果页面只有3-4个的话,可以考虑把全部页面都缓存起来以提高滑动的流畅性
setUserVisibleHint实现延迟加载
如果我们增大了OffscreenPageLimit了,那如果每页的Fragment都需要加装数据(如访问网络),那每个页面预加载的页面都会加载数据。如何实现延迟加载?Fragment的setUserVisibleHint方法就派上用场。以下是setUserVisibleHint的api注释:
/**
* Set a hint to the system about whether this fragment's UI is currently visible
* to the user. This hint defaults to true and is persistent across fragment instance
* state save and restore.
*
* <p>An app may set this to false to indicate that the fragment's UI is
* scrolled out of visibility or is otherwise not directly visible to the user.
* This may be used by the system to prioritize operations such as fragment lifecycle updates
* or loader ordering behavior.</p>
*
* <p><strong>Note:</strong> This method may be called outside of the fragment lifecycle.
* and thus has no ordering guarantees with regard to fragment lifecycle method calls.</p>
*
* @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
* false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
。。。
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
简单地说,就是在Fragment可视性发生变化时,setUserVisibleHint就会被回调,这样的话,我们就可以在此做些文章以实现数据的延迟加载:
boolean mIsVisible = false;
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
mIsVisible = isVisibleToUser;
if (isVisibleToUser) {
lazyLoad();
}
}
void lazyLoad() {
if (mIsVisible && mRecyclerView != null && mAdapter != null && mAdapter.getItemCount() == 0) {
loadData();
}
}
void loadData(){
//load your data here
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
这样,预加载时候因mIsVisible=false而不会真正去加装数据,只有滑动到这个页面时候才会真正去加载数据;如果滑出这个页面又滑动回来,这时候adapter如果有数据的话也不会再去加载数据
FragmentPagerAdapter还是FragmentStatePagerAdapter
FragmentStatePagerAdapter与FragmentPagerAdapter对Fragment的生命周期管理影响不同,简单地说:
如果一个Fragment不在OffscreenPageLimit范围内,那么:
- FragmentPagerAdapter情况下
- 销毁仅仅回调destoryView,而不会回调detach和onDestory
- 再次创该Fragment时候,不会重新attach和onCreate
- FragmentStatePagerAdapter情况下
- 销毁不仅回调destoryView,也会回调detach和onDestory
- 再次创该Fragment时候,需要重新attach和onCreate
FragmentStatePagerAdapter一般用于需要动态加载而且数据量比较大的情况,它可以减少缓存数据。
以下是Api文档对FragmentStatePagerAdapter的说明:
* Implementation of {@link PagerAdapter} that
* uses a {@link Fragment} to manage each page. This class also handles
* saving and restoring of fragment's state.
*
* <p>This version of the pager is more useful when there are a large number
* of pages, working more like a list view. When pages are not visible to
* the user, their entire fragment may be destroyed, only keeping the saved
* state of that fragment. This allows the pager to hold on to much less
* memory associated with each visited page as compared to
* {@link FragmentPagerAdapter} at the cost of potentially more overhead when
* switching between pages.