zoukankan      html  css  js  c++  java
  • 关于ViewPager+Fragment中Fragment不销毁/生命周期

    今天我们的界面大幅改动,最终改成现在主流的Tab类型,和微信有点类似,下面有四个Tab对于四个不一样的模块。

    但是这个四个界面都需要访问网络,并且我们开发框架用的是注解框架,导致对请求网络不好管理。,

    而且又是viewpager+fragment

    我们计划是在第一个页面将四个模板全部初始化,然后放到集合里面,这样即使用户任意切换都不会有问题,因为我们已经初始化了,

    但是用过viewpager的就知道,他会预加载前面和后面的item,但是其他的会销毁掉。

    这样可以避免内存浪费,但是我们不想这样,这样用户体验特别不好,别说产品和测试不同意,我自己也看不过去,

    特别是每次一点入这个tab然后访问下网络,再更新下UI让我都莫名其妙。

    最后还是解决了问题,一行代码。如下;

    • 方案一:设置ViewPager的缓存界面数
    此方案适用于界面数较少的情况,避免缓存界面太多导致内存吃紧。
    方法:
    mPager .setOffscreenPageLimit(2);

    参数:int limit    -    缓存当前界面每一侧的界面数

    以上述为例,当前界面为1,limit = 2,表示缓存2、3两个界面。如此便避免了界面3被销毁。
     
    • 方案二:保存状态并恢复
    此方案适用于可用界面信息可由状态保存和恢复实现的情况。
    在onDestroyView方法内保存相关信息,在onCreateView方法内恢复信息设置。
     
    • 方案三(推荐):复用Fragment的RootView
    此方案适用通用场景,推荐使用。
    步骤1:在onDestroyView方法内把Fragment的RootView从ViewPager中remove
     
     @Override
     public void onDestroyView() {
        LogUtils.d(TAG , "-->onDestroyView");
        super .onDestroyView();
         if (null != FragmentView) {
             ((ViewGroup) mFragmentView.getParent()).removeView(mFragmentView);
        }
     }
     
    步骤2:在onCreateView方法内复用RootView
     
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         LogUtils.d (TAG, "-->onCreateView");
         if (null == mFragmentView) {
              mFragmentView = inflater.inflate(R.layout.fragment, container, false);
             mListView = (ListView) mFragmentView .findViewById(R.id.mm_listview);
            mListView.setAdapter(mAdapter);
          mPbar = (ProgressBar) mFragmentView.findViewById(R.id.pbar_mm_loading);
             mPbar.setVisibility(View.VISIBLE);
        }
      
        return mFragmentView ;
    }

    我省事用了第一种,当然后面改成看第三种。

     补充下,刚刚看了下第一种方式的源码:

    显示这个方法

    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();
            }
        }

     其中我分开放出来:

       private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
    。。。。  
    private static final int DEFAULT_OFFSCREEN_PAGES = 1;

    也就是说,我们设置的数据不是1的话,就调用了populate()方法。

    下面是这个方法的代码:

    首先
       void populate() {
            populate(mCurItem);
        }
    其中mCurItem是当前的item
      private int mCurItem;   // Index of currently displayed page.

    我们看下一个参数的populate()方法:

    void populate(int newCurrentItem) {
            ItemInfo oldCurInfo = null;
            int focusDirection = View.FOCUS_FORWARD;
            if (mCurItem != newCurrentItem) {
                focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
                oldCurInfo = infoForPosition(mCurItem);
                mCurItem = newCurrentItem;
            }
    
            if (mAdapter == null) {
                sortChildDrawingOrder();
                return;
            }
    
            // Bail now if we are waiting to populate.  This is to hold off
            // on creating views from the time the user releases their finger to
            // fling to a new position until we have finished the scroll to
            // that position, avoiding glitches from happening at that point.
            if (mPopulatePending) {
                if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
                sortChildDrawingOrder();
                return;
            }
    
            // Also, don't populate until we are attached to a window.  This is to
            // avoid trying to populate before we have restored our view hierarchy
            // state and conflicting with what is restored.
            if (getWindowToken() == null) {
                return;
            }
    
            mAdapter.startUpdate(this);
    
            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);
    
            if (N != mExpectedAdapterCount) {
                String resName;
                try {
                    resName = getResources().getResourceName(getId());
                } catch (Resources.NotFoundException e) {
                    resName = Integer.toHexString(getId());
                }
                throw new IllegalStateException("The application's PagerAdapter changed the adapter's" +
                        " contents without calling PagerAdapter#notifyDataSetChanged!" +
                        " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N +
                        " Pager id: " + resName +
                        " Pager class: " + getClass() +
                        " Problematic adapter: " + mAdapter.getClass());
            }
    
            // Locate the currently focused item or add it if needed.
            int curIndex = -1;
            ItemInfo curItem = null;
            for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
                final ItemInfo ii = mItems.get(curIndex);
                if (ii.position >= mCurItem) {
                    if (ii.position == mCurItem) curItem = ii;
                    break;
                }
            }
    
            if (curItem == null && N > 0) {
                curItem = addNewItem(mCurItem, curIndex);
            }
    
            // Fill 3x the available width or up to the number of offscreen
            // pages requested to either side, whichever is larger.
            // If we have no current item we have no work to do.
            if (curItem != null) {
                float extraWidthLeft = 0.f;
                int itemIndex = curIndex - 1;
                ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
                final int clientWidth = getClientWidth();
                final float leftWidthNeeded = clientWidth <= 0 ? 0 :
                        2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
                for (int pos = mCurItem - 1; pos >= 0; pos--) {
                    if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
                        if (ii == null) {
                            break;
                        }
                        if (pos == ii.position && !ii.scrolling) {
                            mItems.remove(itemIndex);
                            mAdapter.destroyItem(this, pos, ii.object);
                            if (DEBUG) {
                                Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
                                        " view: " + ((View) ii.object));
                            }
                            itemIndex--;
                            curIndex--;
                            ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
                        }
                    } else if (ii != null && pos == ii.position) {
                        extraWidthLeft += ii.widthFactor;
                        itemIndex--;
                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
                    } else {
                        ii = addNewItem(pos, itemIndex + 1);
                        extraWidthLeft += ii.widthFactor;
                        curIndex++;
                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
                    }
                }
    
                float extraWidthRight = curItem.widthFactor;
                itemIndex = curIndex + 1;
                if (extraWidthRight < 2.f) {
                    ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
                    final float rightWidthNeeded = clientWidth <= 0 ? 0 :
                            (float) getPaddingRight() / (float) clientWidth + 2.f;
                    for (int pos = mCurItem + 1; pos < N; pos++) {
                        if (extraWidthRight >= rightWidthNeeded && pos > endPos) {
                            if (ii == null) {
                                break;
                            }
                            if (pos == ii.position && !ii.scrolling) {
                                mItems.remove(itemIndex);
                                mAdapter.destroyItem(this, pos, ii.object);
                                if (DEBUG) {
                                    Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
                                            " view: " + ((View) ii.object));
                                }
                                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
                            }
                        } else if (ii != null && pos == ii.position) {
                            extraWidthRight += ii.widthFactor;
                            itemIndex++;
                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
                        } else {
                            ii = addNewItem(pos, itemIndex);
                            itemIndex++;
                            extraWidthRight += ii.widthFactor;
                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
                        }
                    }
                }
    
                calculatePageOffsets(curItem, curIndex, oldCurInfo);
            }
    
            if (DEBUG) {
                Log.i(TAG, "Current page list:");
                for (int i=0; i<mItems.size(); i++) {
                    Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
                }
            }
    
            mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
    
            mAdapter.finishUpdate(this);
    
            // Check width measurement of current pages and drawing sort order.
            // Update LayoutParams as needed.
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = getChildAt(i);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                lp.childIndex = i;
                if (!lp.isDecor && lp.widthFactor == 0.f) {
                    // 0 means requery the adapter for this, it doesn't have a valid width.
                    final ItemInfo ii = infoForChild(child);
                    if (ii != null) {
                        lp.widthFactor = ii.widthFactor;
                        lp.position = ii.position;
                    }
                }
            }
            sortChildDrawingOrder();
    
            if (hasFocus()) {
                View currentFocused = findFocus();
                ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
                if (ii == null || ii.position != mCurItem) {
                    for (int i=0; i<getChildCount(); i++) {
                        View child = getChildAt(i);
                        ii = infoForChild(child);
                        if (ii != null && ii.position == mCurItem) {
                            if (child.requestFocus(focusDirection)) {
                                break;
                            }
                        }
                    }
                }
            }
        }

    真长。。。。

    其实也是他自身保存了ItemInfo,然后实现了效果

    然后,。。

    我又用了第一种方法,google写好的,省的麻烦不用白不用,还没有bug.

  • 相关阅读:
    剩余类&完全剩余组
    同余验算法
    一种快速余数求法
    同余的性质II
    同余初步
    求N个数的最小公倍数
    N个数GCD求解法
    快速求解GCD的三个Trick
    质数的几个有趣问题
    等比数列求和公式
  • 原文地址:https://www.cnblogs.com/itpepe/p/4932540.html
Copyright © 2011-2022 走看看