1. 程式人生 > >淺談viewpager+fragment快取問題的優化

淺談viewpager+fragment快取問題的優化

問題是這樣的,專案中有 用到tablayout+viewpager+fragment這個頂部導航模組,切換的tab大概有十個,除了第一tab的fragment,其他tab的fragment都是同一個class只是資料不同。因為是電商的app,所以圖片特別多等等原因的佔用記憶體比較大,再加上這塊fragment物件多因此這塊的優化需求就有了。
ps:公司專案原因,不便傳截圖。

專案中最初是這樣的,廢話不多說直接上程式碼

@Override
    public Fragment getItem(int position) {
        if (position == 0
) { return new HomeFragment(); } else { return new OtherCategoryFragment.newInstance(); } }
    public static OtherCategoryFragment newInstance() {
        OtherCategoryFragment otherCategoryFragment = new OtherCategoryFragment();
        return otherCategoryFragment;
    }

viewpageradapter中getitem中每次都是呼叫fragment的newInstance方法,然而newInstance方法都是直接new一個物件。我的天啊,這能忍,豈不是每次切換都會new物件的。於是我開始了第一次優化:

    @Override
    public Fragment getItem(int position) {
        Fragment fragment;
        if (fragments.size() <= position) {
            if (position == 0) {
                fragment = PrimeHomeFragment.newInstance();
            } else
{ fragment = PrimeOtherCategoryFragment.newInstance(categories.get(position).id, position); } fragments.add(fragment); } else { fragment = fragments.get(position); } return fragment; }

其實我就是加了個ArrayList fragments來儲存new出來的fragment,當第二次使用該fragment時候直接取出來不再是油重新new一個物件。眼尖的人或許看出來了這種做法too young,因為viewpager會自己管理fragments,預設快取(預載入)DEFAULT_OFFSCREEN_PAGES =1參賽,其他頁面fragment會自動finish掉,所以我用list儲存fragment並沒什麼卵用的,超出快取數還是會繼續new。於是開啟了繼續優化

 viewPager.setOffscreenPageLimit(fragmentList.size()-1);

上面提到過viewpager會自動管理快取的,預設為DEFAULT_OFFSCREEN_PAGES=1。那我設定全部快取不就ok了麼,嗯,問題是解決了,然而產品會殺了你,因為載入第一個頁面時候把把所有頁面預加載出來才會完整顯示第一個頁面,所以第一個頁面會等很久很久。於是開始了繼續優化


    @Override
    public Fragment getItem(int position) {
        Fragment fragment;
        if (fragments.size() <= position) {
            if (position == 0) {
                fragment = PrimeHomeFragment.newInstance();
            } else {
                fragment = PrimeOtherCategoryFragment.newInstance(categories.get(position).id, position);
            }
            fragments.add(fragment);

        } else {
            // return PrimeOtherCategoryFragment.newInstance(categories.get(position).id);
            fragment = fragments.get(position);
            // return fragments.get(position);
        }
        //儲存Fragment
        Bundle bundle = new Bundle();
        bundle.putString("id", "" + position);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public Fragment instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container,
                position);
        fm.beginTransaction().show(fragment).commit();
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // super.destroyItem(container, position, object);
        fm.beginTransaction().hide(fragments.get(position)).commit();
    }

這種優化的基本思路是底部導航欄的思路,採用hide和show來控制。也就是第一次加載出來後,再到該fragment就通過呼叫show方法來顯示。當然確定也就是super.destroyItem沒被呼叫,也就是fragment物件會一直存在那,記憶體佔用問題沒很好的解決,於是再再下次優化開始

思路:其實針對我們專案本身tab切換的fragment雖然十來個很多,可除了第一個其他的是同一個fragment只是資料不同而已。於是listview的優化思路出來了,即共用ui,切換介面其實只是刷資料而已,具體我還沒去實現只有這個思路,大概列出幾個注意的點:

  • 自己管理viewpager對fragment的new和destory管理
  • 自行設計fragmnet與pageradapter間的通訊

ps:有更好思路的,可以說說意見一起試試