zoukankan      html  css  js  c++  java
  • 实现ViewPager懒加载的三种方法

    在项目中ViewPager和Fragment接口框架已经是处处可见,但是在使用中,我们肯定不希望用户在当前页面时就在前后页面的数据,加入数据量很大,而用户又不愿意左右滑动浏览,那么这时候ViewPager中本来充满善意的预加载就有点令人不爽了。我们能做的就是屏蔽掉ViewPager的预加载机制。虽然ViewPager中提供的有

    setOffscreenPageLimit()来控制其预加载的数目,但是当设置为0后我们发现其根本没效果,这个的最小值就是1,也就是你只能最少前后各预加载一页。那么,这时候就得另觅方法了。


    以下三种方法是我在学习和项目中尝试过的,需求实现了,但各有千秋,可结合不同场景使用。因为打算慢慢养成写博客的习惯,就总结在此,也希望对他人有所借鉴。


    方法一 

    在Fragment可见时请求数据。此方案仍预加载了前后的页面,但是没有请求数据,只有进入到当前Framgent时才请求数据。

    优点:实现了数据的懒加载

    缺点:一次仍是三个Framgment对象,不是完全意义的懒加载

    1. public class FragmentSample extends Fragment{

    2.    ...  

    3.    @Override

    4.    public void setUserVisibleHint(boolean isVisibleToUser) {

    5.        super.setUserVisibleHint(isVisibleToUser);

    6.        if (isVisibleToUser) {

    7.            requestData(); // 在此请求数据

    8.        }

    9.    }

    10.    ...

    11. }


    方法二

    直接修改ViewPager源码。通过查看ViewPager源码可知,控制其预加载的是一个常量

    DEFAULT_OFFSCREEN_PAGES,其默认值为1,表示当前页面前后各预加载一个页面,在这里我们直接将其设置为0即可,即去掉预加载。但是,这样有一个问题,那就是在使用其他控件时需要传入ViewPager时,这个就不能用了。

    优点:完全屏蔽掉了预加载

    缺点:应用太受限制,比如使用ViewPagerIndicator时需要传入ViewPager对象,这时傻眼了。

    1. // 注意,这是直接拷贝的ViewPager的源码,只修改了注释处的代码
    2. public class LazyViewPager extends ViewGroup {
    3. private static final String TAG = "LazyViewPager";
    4. private static final boolean DEBUG = false;
    5. private static final boolean USE_CACHE = false;
    6. // 默认为1,即前后各预加载一个页面,设置为0去掉预加载
    7. private static final int DEFAULT_OFFSCREEN_PAGES = 0;
    8. private static final int MAX_SETTLE_DURATION = 600; // ms
    9. static class ItemInfo {
    10. Object object;
    11. int position;
    12. boolean scrolling;
    13. }
    14. private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>() {
    15. @Override
    16. public int compare(ItemInfo lhs, ItemInfo rhs) {
    17. return lhs.position - rhs.position;
    18. }
    19. };
    20. ............
    21. }


    方法三

    直接继承ViewPager,结合PagerAdapter实现懒加载。该方案是我用到的最完善的方法,完全的懒加载,每次只会建立一个Fragment对象。

    优点:完全屏蔽预加载

    缺点:稍微复杂,但是人家已经造好的轮子,直接用吧,很简洁

    开源库:https://github.com/lianghanzhen/LazyViewPager

    这个库就4个类,作者通过继承ViewPager(保证其普适性)、自定义ViewPagerAdapter和 LazyFragmentPagerAdapter以及设置懒加载的标记接口,很好的实现了懒加载。感谢作者。

    在此贴出关键代码,有兴趣的同学可以学习下。

    LazyViewPager:

    1. public class LazyViewPager extends ViewPager {
    2. private static final float DEFAULT_OFFSET = 0.5f;
    3. private LazyPagerAdapter mLazyPagerAdapter;
    4. private float mInitLazyItemOffset = DEFAULT_OFFSET;
    5. public LazyViewPager(Context context) {
    6. super(context);
    7. }
    8. public LazyViewPager(Context context, AttributeSet attrs) {
    9. super(context, attrs);
    10. TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LazyViewPager);
    11. setInitLazyItemOffset(a.getFloat(R.styleable.LazyViewPager_init_lazy_item_offset, DEFAULT_OFFSET));
    12. a.recycle();
    13. }
    14. /**
    15. * change the initLazyItemOffset
    16. * @param initLazyItemOffset set mInitLazyItemOffset if {@code 0 < initLazyItemOffset <= 1}
    17. */
    18. public void setInitLazyItemOffset(float initLazyItemOffset) {
    19. if (initLazyItemOffset > 0 && initLazyItemOffset <= 1) {
    20. mInitLazyItemOffset = initLazyItemOffset;
    21. }
    22. }
    23. @Override
    24. public void setAdapter(PagerAdapter adapter) {
    25. super.setAdapter(adapter);
    26. mLazyPagerAdapter = adapter != null && adapter instanceof LazyPagerAdapter ? (LazyPagerAdapter) adapter : null;
    27. }
    28. @Override
    29. protected void onPageScrolled(int position, float offset, int offsetPixels) {
    30. if (mLazyPagerAdapter != null) {
    31. if (getCurrentItem() == position) {
    32. int lazyPosition = position + 1;
    33. if (offset >= mInitLazyItemOffset && mLazyPagerAdapter.isLazyItem(lazyPosition)) {
    34. mLazyPagerAdapter.startUpdate(this);
    35. mLazyPagerAdapter.addLazyItem(this, lazyPosition);
    36. mLazyPagerAdapter.finishUpdate(this);
    37. }
    38. } else if (getCurrentItem() > position) {
    39. int lazyPosition = position;
    40. if (1 - offset >= mInitLazyItemOffset && mLazyPagerAdapter.isLazyItem(lazyPosition)) {
    41. mLazyPagerAdapter.startUpdate(this);
    42. mLazyPagerAdapter.addLazyItem(this, lazyPosition);
    43. mLazyPagerAdapter.finishUpdate(this);
    44. }
    45. }
    46. }
    47. super.onPageScrolled(position, offset, offsetPixels);
    48. }
    49. }

    1. public abstract class LazyFragmentPagerAdapter extends LazyPagerAdapter<Fragment> {
    2. private static final String TAG = "LazyFragmentPagerAdapter";
    3. private static final boolean DEBUG = false;
    4. private final FragmentManager mFragmentManager;
    5. private FragmentTransaction mCurTransaction = null;
    6. public LazyFragmentPagerAdapter(FragmentManager fm) {
    7. mFragmentManager = fm;
    8. }
    9. @Override
    10. public void startUpdate(ViewGroup container) {
    11. }
    12. @Override
    13. public Object instantiateItem(ViewGroup container, int position) {
    14. if (mCurTransaction == null) {
    15. mCurTransaction = mFragmentManager.beginTransaction();
    16. }
    17. final long itemId = getItemId(position);
    18. // Do we already have this fragment?
    19. String name = makeFragmentName(container.getId(), itemId);
    20. Fragment fragment = mFragmentManager.findFragmentByTag(name);
    21. if (fragment != null) {
    22. if (DEBUG)
    23. Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
    24. mCurTransaction.attach(fragment);
    25. } else {
    26. fragment = getItem(container, position);
    27. if (fragment instanceof Laziable) {
    28. mLazyItems.put(position, fragment);
    29. } else {
    30. mCurTransaction.add(container.getId(), fragment, name);
    31. }
    32. }
    33. if (fragment != getCurrentItem()) {
    34. fragment.setMenuVisibility(false);
    35. fragment.setUserVisibleHint(false);
    36. }
    37. return fragment;
    38. }
    39. @Override
    40. public void destroyItem(ViewGroup container, int position, Object object) {
    41. if (mCurTransaction == null) {
    42. mCurTransaction = mFragmentManager.beginTransaction();
    43. }
    44. if (DEBUG)
    45. Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object + " v=" + ((Fragment) object).getView());
    46. final long itemId = getItemId(position);
    47. String name = makeFragmentName(container.getId(), itemId);
    48. if (mFragmentManager.findFragmentByTag(name) == null) {
    49. mCurTransaction.detach((Fragment) object);
    50. } else {
    51. mLazyItems.remove(position);
    52. }
    53. }
    54. @Override
    55. public Fragment addLazyItem(ViewGroup container, int position) {
    56. Fragment fragment = mLazyItems.get(position);
    57. if (fragment == null)
    58. return null;
    59. final long itemId = getItemId(position);
    60. String name = makeFragmentName(container.getId(), itemId);
    61. if (mFragmentManager.findFragmentByTag(name) == null) {
    62. if (mCurTransaction == null) {
    63. mCurTransaction = mFragmentManager.beginTransaction();
    64. }
    65. mCurTransaction.add(container.getId(), fragment, name);
    66. mLazyItems.remove(position);
    67. }
    68. return fragment;
    69. }
    70. @Override
    71. public void finishUpdate(ViewGroup container) {
    72. if (mCurTransaction != null) {
    73. mCurTransaction.commitAllowingStateLoss();
    74. mCurTransaction = null;
    75. mFragmentManager.executePendingTransactions();
    76. }
    77. }
    78. @Override
    79. public boolean isViewFromObject(View view, Object object) {
    80. return ((Fragment) object).getView() == view;
    81. }
    82. public long getItemId(int position) {
    83. return position;
    84. }
    85. private static String makeFragmentName(int viewId, long id) {
    86. return "android:switcher:" + viewId + ":" + id;
    87. }
    88. /**
    89. * mark the fragment can be added lazily
    90. */
    91. public interface Laziable {
    92. }
    93. }
    最后提醒一下:填充LazyViewPager的Fragment一定要实现接口LazyFragmentPagerAdapter.Laziable。


    以上。

  • 相关阅读:
    7.24总结
    7.23总结
    7.22总结
    。。。
    7.21总结
    7.20总结
    7.19总结
    大假期第四次测试总结
    大假期第三次测试
    题目分享k
  • 原文地址:https://www.cnblogs.com/vegetate/p/9997203.html
Copyright © 2011-2022 走看看