平方X 发表于 2016-5-12 11:07:04

viewpager和fragment的懒加载。

以这个为例
http://www.2cto.com/kf/201501/368954.html
①BaseFragment 中重写setUserVisibleHint()设置标记,在加载时判断。
//关闭预加载,默认一次只加载一个Fragment
②mViewPager.setOffscreenPageLimit(1);
但是,这个注释是不正确的。具体打log可以发现,加载0时会预加载1,加载2时会加载1和3.
我们看源码
1,首先是方法实现

    /**
   * 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>
   *
   * @param limit How many pages will be kept offscreen in an idle state.
   */
    public void setOffscreenPageLimit(int limit) {
      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();
      }
    }

2,这个mOffscreenPageLimit,在 void populate(int newCurrentItem)用到,用来计算start和end,然后根据start和end分别做了循环(具体参见源代码)

      final int pageLimit = mOffscreenPageLimit;
      final int startPos = Math.max(0, mCurItem - pageLimit);
      final int N = mAdapter.getCount();
      final int endPos = Math.min(N-1, mCurItem + pageLimit);

最后在循环中,如果为null的,执行
                  ii = addNewItem(pos, itemIndex + 1);
3,在
ItemInfo addNewItem(int position, int index) {
      ItemInfo ii = new ItemInfo();
      ii.position = position;
      ii.object = mAdapter.instantiateItem(this, position);
      ii.widthFactor = mAdapter.getPageWidth(position);
      if (index < 0 || index >= mItems.size()) {
            mItems.add(ii);
      } else {
            mItems.add(index, ii);
      }
      return ii;
    }
4,在adapter中,FragmentPagerAdapter中

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
      if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
      }

      final long itemId = getItemId(position);

      // Do we already have this fragment?
      String name = makeFragmentName(container.getId(), itemId);
      Fragment fragment = mFragmentManager.findFragmentByTag(name);
      if (fragment != null) {
            if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
            mCurTransaction.attach(fragment);
      } else {
            fragment = getItem(position);
            if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
            mCurTransaction.add(container.getId(), fragment,
                  makeFragmentName(container.getId(), itemId));
      }
      if (fragment != mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false);
            fragment.setUserVisibleHint(false);
      }

      return fragment;
    }
5,所以我们看到 fragment = getItem(position);
整理一下,在getItem中加载的fragment,依次被FragmentPagerAdapter中的instantiateItem()方法,ViewPager中的addNewItem方法、populate()方法调用。
调用时根据mOffscreenPageLimit预加载,而这个最小是1,所以肯定会预加载。
在最上面的例子中,已经new了,只是没有初始化等。
所以如果我们要想设置为0。只能自定义一个,然后改为0就好了。
页: [1]
查看完整版本: viewpager和fragment的懒加载。