欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android性能優(yōu)化之ViewPagers?+?Fragment緩存優(yōu)化

 更新時(shí)間:2022年08月29日 11:24:30   作者:Ghelper???????  
這篇文章主要介紹了Android性能優(yōu)化之ViewPagers+Fragment緩存優(yōu)化,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言

大家看標(biāo)題,可能會(huì)有點(diǎn)兒懵,什么是ViewPagers,因?yàn)樵诤芫弥?,我們使用的都是ViewPager,但是現(xiàn)在更多的是在用ViewPager2,因此用ViewPagers(ViewPager、ViewPager2)來(lái)代替兩者,主要介紹兩者的區(qū)別。

ViewPagers嵌套Fragment架構(gòu),在我們常用的App中隨處可見(jiàn),抖音的首頁(yè)、各大電商app首頁(yè)(淘寶、京東、拼多多)等,通過(guò)左右滑動(dòng)切換Tab;但因?yàn)閂iewPager的預(yù)加載機(jī)制存在,

我們先看下ViewPager的源碼:

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

當(dāng)我們?cè)O(shè)置offscreenPageLimit(離屏加載)的數(shù)值時(shí),我們可以看到limit的值是有限制,不能小于DEFAULT_OFFSCREEN_PAGES

private static final int DEFAULT_OFFSCREEN_PAGES = 1;

那么就意味著ViewPager默認(rèn)支持預(yù)加載,我們看下面這張圖

如果紅色區(qū)域默認(rèn)為首頁(yè),根據(jù)ViewPager默認(rèn)預(yù)加載的閾值,那么左右兩邊的頁(yè)面同樣也會(huì)被加載,如果有網(wǎng)絡(luò)請(qǐng)求,也就是說(shuō),我們沒(méi)有打開(kāi)左邊的頁(yè)面,它已經(jīng)默認(rèn)進(jìn)行了網(wǎng)絡(luò)請(qǐng)求,這種體驗(yàn)是非常差的,因?yàn)闀?huì)在暗地里消耗流量。

理想情況下,我們需要的是打開(kāi)某個(gè)頁(yè)面的時(shí)候才去加載,這里就需要通過(guò)懶加載的方式優(yōu)化。

1 ViewPager懶加載優(yōu)化

1.1 ViewPager的緩存機(jī)制

很多時(shí)候,我們?cè)谑褂肍ragment的時(shí)候,發(fā)現(xiàn)打開(kāi)過(guò)的頁(yè)面再回來(lái),頁(yè)面沒(méi)有重建刷新,很多人覺(jué)得是Fragment是有緩存的,其實(shí)并不是Fragment有緩存,而是ViewPager具備緩存能力;

如果有小伙伴使用過(guò)單Activity + 多Fragment架構(gòu)的時(shí)候就會(huì)發(fā)現(xiàn),打開(kāi)過(guò)的頁(yè)面再次返回的時(shí)候,F(xiàn)ragment會(huì)被重建,所以?xún)煞N架構(gòu)都有利弊,關(guān)鍵看我們?cè)趺催x擇,下面我們看下ViewPager的緩存機(jī)制。

public void setAdapter(@Nullable PagerAdapter adapter) {
    if (mAdapter != null) {
        ①
        mAdapter.setViewPagerObserver(null);
        mAdapter.startUpdate(this);
        for (int i = 0; i < mItems.size(); i++) {
            final ItemInfo ii = mItems.get(i);
            mAdapter.destroyItem(this, ii.position, ii.object);
        }
        mAdapter.finishUpdate(this);
        mItems.clear();
        removeNonDecorViews();
        mCurItem = 0;
        scrollTo(0, 0);
    }
    ②
    final PagerAdapter oldAdapter = mAdapter;
    mAdapter = adapter;
    mExpectedAdapterCount = 0;

    ③
    if (mAdapter != null) {
        if (mObserver == null) {
            mObserver = new PagerObserver();
        }
        mAdapter.setViewPagerObserver(mObserver);
        mPopulatePending = false;
        final boolean wasFirstLayout = mFirstLayout;
        mFirstLayout = true;
        mExpectedAdapterCount = mAdapter.getCount();
        if (mRestoredCurItem >= 0) {
            mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
            setCurrentItemInternal(mRestoredCurItem, false, true);
            mRestoredCurItem = -1;
            mRestoredAdapterState = null;
            mRestoredClassLoader = null;
        } else if (!wasFirstLayout) {
            ④
            populate();
        } else {
            ⑤
            requestLayout();
        }
    }

    // Dispatch the change to any listeners
    if (mAdapterChangeListeners != null && !mAdapterChangeListeners.isEmpty()) {
        for (int i = 0, count = mAdapterChangeListeners.size(); i < count; i++) {
            mAdapterChangeListeners.get(i).onAdapterChanged(this, oldAdapter, adapter);
        }
    }
}

核心方法就是setAdapter,像RecyclerView一樣,因?yàn)闀?huì)有緩存,所以當(dāng)頁(yè)面滑動(dòng)的時(shí)候,如果緩存中存在頁(yè)面,那么就會(huì)從緩存中取,如果沒(méi)有,就需要去創(chuàng)建新的頁(yè)面,所以我們先來(lái)關(guān)注一下PagerAdapter

public abstract class PagerAdapter {
    private final DataSetObservable mObservable = new DataSetObservable();
    private DataSetObserver mViewPagerObserver;

    public static final int POSITION_UNCHANGED = -1;
    public static final int POSITION_NONE = -2;

    public abstract int getCount();
    //開(kāi)始更新
    public void startUpdate(@NonNull ViewGroup container) {
        startUpdate((View) container);
    }
    //初始化頁(yè)面
    @NonNull
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        return instantiateItem((View) container, position);
    }
    //銷(xiāo)毀頁(yè)面
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        destroyItem((View) container, position, object);
    }
    //結(jié)束刷新
    public void finishUpdate(@NonNull ViewGroup container) {
        finishUpdate((View) container);
    }
}

PagerAdapter是一個(gè)抽象類(lèi),那么這些方法肯定是具體實(shí)現(xiàn)類(lèi)實(shí)現(xiàn),如果我們?cè)谑褂肰iewPager嵌套Fragment的時(shí)候,使用的是FragmentPageAdapter

接著回到setAdapter方法中:

  • ①:有一個(gè)全局變量 mAdapter,如果是第一個(gè)加載進(jìn)來(lái),那么mAdapter是空的,走到②
  • ②:這里就是將我們傳入的adapter給mAdapter賦值
  • ③:這個(gè)時(shí)候mAdapter不為空,這里需要關(guān)注幾個(gè)參數(shù):
wasFirstLayout = true
mRestoredCurItem = -1

所以這里直接走到⑤,調(diào)用requestLayout方法,會(huì)執(zhí)行到onMeasure,在這個(gè)方法中,會(huì)執(zhí)行populate方法(這個(gè)大家自己去爬樓)

populate干了什么呢?代碼太多了就不貼出來(lái)了,直接上圖:

如果是默認(rèn)緩存(mOffscreenPageLimit = 1),那么在mItems就會(huì)緩存3個(gè)Fragment

private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();

當(dāng)頁(yè)面滑動(dòng)時(shí),page2成為了當(dāng)前頁(yè),那么ViewPager的populate做了什么操作呢?

  • (1)首先page3會(huì)被預(yù)加載,這個(gè)時(shí)候調(diào)用了PagerAdapter的instantiateItem方法新建頁(yè)面,并放在mItems集合中,并且設(shè)置為不可見(jiàn)的狀態(tài)(setUserVisibleHint(false)),所有緩存中不可見(jiàn)的頁(yè)面同理(2)page1就會(huì)從緩存中移除,調(diào)用了PagerAdapter的destroyItem方法,curPage會(huì)成為mItems中第一個(gè)緩存對(duì)象;
  • (3)將page2設(shè)置為當(dāng)前展示的Fragment

因此populate干的主要工作就是,隨著頁(yè)面的滑動(dòng),將Page從緩存中移除銷(xiāo)毀,或者將新頁(yè)面新建加入緩存中。

1.2 ViewPager懶加載方案

如上所述,ViewPager默認(rèn)就是開(kāi)啟預(yù)加載的,而且默認(rèn)最多能夠緩存3個(gè)Fragment頁(yè)面,那么為了避免流量的消耗,需要我們針對(duì)預(yù)加載這種情況進(jìn)行頁(yè)面懶加載,只有當(dāng)頁(yè)面可見(jiàn)的時(shí)候,才能加載數(shù)據(jù)。

class MainLazyLoadAdapter(
    fragmentManager: FragmentManager,
    val fragments:MutableList<Fragment>
) : FragmentPagerAdapter(fragmentManager) {
    override fun getCount(): Int {
        return fragments.size
    }

    override fun getItem(position: Int): Fragment {
        return fragments[position]
    }
}
class LazyFragment(val index:Int) : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.e("TAG","LazyFragment $index onCreate")
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        Log.e("TAG","LazyFragment $index onCreateView")
        return inflater.inflate(R.layout.fragment_lazy, container, false)
    }

}
val fragments = mutableListOf<Fragment>()
for (index in 0..5) {
    fragments.add(LazyFragment(index))
}
vp_lazy_load.adapter = MainLazyLoadAdapter(supportFragmentManager, fragments)

首先我們先看默認(rèn)預(yù)加載狀態(tài),驗(yàn)證之前源碼中的原理:

//第一次進(jìn)來(lái)
2022-08-28 13:41:15.759 12677-12677/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 13:41:15.760 12677-12677/com.lay.image_process E/TAG: LazyFragment 0 onCreateView
2022-08-28 13:41:15.783 12677-12677/com.lay.image_process E/TAG: LazyFragment 1 onCreate
2022-08-28 13:41:15.784 12677-12677/com.lay.image_process E/TAG: LazyFragment 1 onCreateView

我們看到第一次進(jìn)來(lái),第二個(gè)Fragment被加載進(jìn)來(lái),然后右滑,第三個(gè)Fragment被加載

2022-08-28 13:41:15.759 12677-12677/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 13:41:15.760 12677-12677/com.lay.image_process E/TAG: LazyFragment 0 onCreateView
2022-08-28 13:41:15.783 12677-12677/com.lay.image_process E/TAG: LazyFragment 1 onCreate
2022-08-28 13:41:15.784 12677-12677/com.lay.image_process E/TAG: LazyFragment 1 onCreateView
2022-08-28 13:48:45.248 12677-12677/com.lay.image_process E/TAG: LazyFragment 2 onCreate
2022-08-28 13:48:45.250 12677-12677/com.lay.image_process E/TAG: LazyFragment 2 onCreateView

當(dāng)我們滑到第4個(gè)Fragment的時(shí)候,左滑回到第3個(gè)Fragment,發(fā)現(xiàn)并沒(méi)有重建是因?yàn)榫彺娴脑?,因?yàn)榛降?個(gè)Fragment的時(shí)候,第2個(gè)Fragment已經(jīng)被銷(xiāo)毀了,再回到第3個(gè)Fragment的時(shí)候,第2個(gè)Fragment被重建,走了onCreateView方法

2022-08-28 13:41:15.759 12677-12677/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 13:41:15.760 12677-12677/com.lay.image_process E/TAG: LazyFragment 0 onCreateView
2022-08-28 13:41:15.783 12677-12677/com.lay.image_process E/TAG: LazyFragment 1 onCreate
2022-08-28 13:41:15.784 12677-12677/com.lay.image_process E/TAG: LazyFragment 1 onCreateView
2022-08-28 13:48:45.248 12677-12677/com.lay.image_process E/TAG: LazyFragment 2 onCreate
2022-08-28 13:48:45.250 12677-12677/com.lay.image_process E/TAG: LazyFragment 2 onCreateView
2022-08-28 13:50:00.439 12677-12677/com.lay.image_process E/TAG: LazyFragment 3 onCreate
2022-08-28 13:50:00.440 12677-12677/com.lay.image_process E/TAG: LazyFragment 3 onCreateView
2022-08-28 13:50:01.344 12677-12677/com.lay.image_process E/TAG: LazyFragment 4 onCreate
2022-08-28 13:50:01.345 12677-12677/com.lay.image_process E/TAG: LazyFragment 4 onCreateView
2022-08-28 13:50:03.315 12677-12677/com.lay.image_process E/TAG: LazyFragment 1 onCreateView

首先我們先看下,Adapter重建Fragment的時(shí)候的核心代碼

public Object instantiateItem(@NonNull 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);
        if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
            mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
        } else {
            //關(guān)鍵代碼
            fragment.setUserVisibleHint(false);
        }
    }

    return fragment;
}

我們可以看到,當(dāng)前Fragment如果被創(chuàng)建但是沒(méi)有在當(dāng)前頁(yè)面展示的時(shí)候,調(diào)用了fragment.setUserVisibleHint(false),也就是說(shuō)setUserVisibleHint能夠監(jiān)聽(tīng)當(dāng)前Fragment是否可見(jiàn)

所以我們對(duì)Fragment進(jìn)行改造:

class LazyFragment(val index:Int) : Fragment() {

    //判斷當(dāng)前頁(yè)面是否可見(jiàn)
    private var isShow = false
    //判斷頁(yè)面是否創(chuàng)建成功
    private var isViewCreated = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.e("TAG","LazyFragment $index onCreate")
    }
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        Log.e("TAG","LazyFragment $index onCreateView")
        return inflater.inflate(R.layout.fragment_lazy, container, false)
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        isViewCreated = true
        lazyLoad()
    }
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        Log.e("TAG","LazyFragment $index isVisibleToUser $isVisibleToUser")
        if(isVisibleToUser){
            isShow = true
            //才有資格去懶加載
            lazyLoad()
        }else{
            isShow = false
        }
    }
    private fun lazyLoad() {
        if(isViewCreated && isShow){
            Log.e("TAG","Fragment $index loadData")
        }
    }
    override fun onDestroy() {
        super.onDestroy()
        isViewCreated = false
        isShow = false
    }
}

如果按照之前的方式,當(dāng)調(diào)用onViewCreated方法的時(shí)候,我們就會(huì)加載數(shù)據(jù);做了懶加載處理之后,重寫(xiě)了setUserVisibleHint方法,當(dāng)前頁(yè)面可見(jiàn)的時(shí)候,才有資格去加載數(shù)據(jù),這樣即便創(chuàng)建了Fragment,但是如果不可見(jiàn)就不會(huì)加載數(shù)據(jù)

2022-08-28 14:06:29.776 25904-25904/com.lay.image_process E/TAG: LazyFragment 0 isVisibleToUser false
2022-08-28 14:06:29.776 25904-25904/com.lay.image_process E/TAG: LazyFragment 1 isVisibleToUser false
2022-08-28 14:06:29.776 25904-25904/com.lay.image_process E/TAG: LazyFragment 0 isVisibleToUser true
2022-08-28 14:06:29.782 25904-25904/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 14:06:29.783 25904-25904/com.lay.image_process E/TAG: LazyFragment 0 onCreateView
2022-08-28 14:06:29.796 25904-25904/com.lay.image_process E/TAG: Fragment 0 loadData
2022-08-28 14:06:29.805 25904-25904/com.lay.image_process E/TAG: LazyFragment 1 onCreate
2022-08-28 14:06:29.805 25904-25904/com.lay.image_process E/TAG: LazyFragment 1 onCreateView
2022-08-28 14:06:59.395 25904-25904/com.lay.image_process E/TAG: LazyFragment 2 isVisibleToUser false
2022-08-28 14:06:59.396 25904-25904/com.lay.image_process E/TAG: LazyFragment 0 isVisibleToUser false
2022-08-28 14:06:59.396 25904-25904/com.lay.image_process E/TAG: LazyFragment 1 isVisibleToUser true
2022-08-28 14:06:59.396 25904-25904/com.lay.image_process E/TAG: Fragment 1 loadData
2022-08-28 14:06:59.399 25904-25904/com.lay.image_process E/TAG: LazyFragment 2 onCreate
2022-08-28 14:06:59.400 25904-25904/com.lay.image_process E/TAG: LazyFragment 2 onCreateView

通過(guò)日志我們可以看到,當(dāng)首次進(jìn)入的時(shí)候,雖然Fragment 1 被創(chuàng)建了,但是并沒(méi)有加載數(shù)據(jù)。

這里有個(gè)問(wèn)題,既然可見(jiàn)之后就能加載數(shù)據(jù),那么我只在setUserVisibleHint的時(shí)候,判斷是否可見(jiàn)來(lái)去加載數(shù)據(jù)?

其實(shí)是不可以的,通過(guò)日志我們能夠發(fā)現(xiàn),setUserVisibleHint是早于onCreate方法調(diào)用的,也就是說(shuō)在頁(yè)面還沒(méi)有創(chuàng)建時(shí),去加載數(shù)據(jù)有可能導(dǎo)致頁(yè)面元素找不到發(fā)生空指針異常。

2 ViewPager2與ViewPager的區(qū)別

上一小節(jié),我們介紹了ViewPager的加載機(jī)制和緩存機(jī)制,那么我們把整套頁(yè)面搬過(guò)來(lái),唯一發(fā)生變化的就是將ViewPager轉(zhuǎn)換為ViewPager2

class MainLazyLoadAdapter2(
    activity: FragmentActivity,
    val fragments: MutableList<Fragment>
) : FragmentStateAdapter(activity) {
    override fun getItemCount(): Int {
        return fragments.size
    }
    override fun createFragment(position: Int): Fragment {
        return fragments[position]
    }

}

ViewPager2的適配器使用的是FragmentStateAdapter,因?yàn)镕ragmentStateAdapter繼承了RecyclerView.Adapter,因此支持了橫向滑動(dòng)和豎向滑動(dòng)

val fragments = mutableListOf<Fragment>()
for (index in 0..5) {
    fragments.add(LazyFragment(index))
}
vp_lazy_load = findViewById(R.id.vp_lazy_load)
vp_lazy_load.adapter = MainLazyLoadAdapter2(this, fragments)

用同樣的方式設(shè)置了適配器,我們看下日志輸出,就會(huì)發(fā)現(xiàn),咦?怎么跟ViewPager不一樣了

2022-08-28 14:47:11.790 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 14:47:11.792 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreateView

剛進(jìn)來(lái)的時(shí)候,只有Fragment 1 加載了頁(yè)面,并沒(méi)有新建緩存頁(yè)面,當(dāng)我滑動(dòng)到下一頁(yè)的時(shí)候,也只有下一頁(yè)的頁(yè)面進(jìn)行了重建

2022-08-28 14:47:11.790 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 14:47:11.792 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreateView
2022-08-28 14:47:13.948 15514-15514/com.lay.image_process E/TAG: LazyFragment 1 onCreate
2022-08-28 14:47:13.948 15514-15514/com.lay.image_process E/TAG: LazyFragment 1 onCreateView

ViewPager2沒(méi)有預(yù)加載機(jī)制嗎?這里我們就需要看源碼了,直接奔向setOffscreenPageLimit方法,我們看到跟ViewPager的setOffscreenPageLimit方法是不一樣的

public void setOffscreenPageLimit(@OffscreenPageLimit int limit) {
    if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) {
        throw new IllegalArgumentException(
                "Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0");
    }
    mOffscreenPageLimit = limit;
    // Trigger layout so prefetch happens through getExtraLayoutSize()
    mRecyclerView.requestLayout();
}
public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1;

這里的判斷條件 limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT,有一個(gè)數(shù)值能夠通過(guò),就是-1,這就意味著,ViewPager2默認(rèn)是不支持預(yù)加載的

但是ViewPager2的緩存策略還是存在,因?yàn)槔^承了RecyclerView的Adapter,所以緩存復(fù)用機(jī)制是跟RecyclerView一致的,默認(rèn)mViewCaches緩存池的大小是3

2022-08-28 15:30:00.579 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 15:30:00.579 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreateView
2022-08-28 15:30:03.883 15514-15514/com.lay.image_process E/TAG: LazyFragment 1 onCreate
2022-08-28 15:30:03.884 15514-15514/com.lay.image_process E/TAG: LazyFragment 1 onCreateView
2022-08-28 15:30:05.064 15514-15514/com.lay.image_process E/TAG: LazyFragment 2 onCreate
2022-08-28 15:30:05.064 15514-15514/com.lay.image_process E/TAG: LazyFragment 2 onCreateView
2022-08-28 15:30:08.997 15514-15514/com.lay.image_process E/TAG: LazyFragment 3 onCreate
2022-08-28 15:30:08.997 15514-15514/com.lay.image_process E/TAG: LazyFragment 3 onCreateView
2022-08-28 15:30:20.005 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreate
2022-08-28 15:30:20.005 15514-15514/com.lay.image_process E/TAG: LazyFragment 0 onCreateView

當(dāng)我們滑動(dòng)到第4個(gè)Fragment的時(shí)候,注意這里跟ViewPager不一樣的是,ViewPager的緩存是緩存當(dāng)前頁(yè)的左右兩邊,但是ViewPager2就是RecyclerView的緩存機(jī)制,順序緩存;

當(dāng)滑動(dòng)到第4個(gè)Fragment的時(shí)候,因?yàn)榫彺娉卮笮?,因此LazyFragment 0 就會(huì)從緩存池中移除,當(dāng)再次滑動(dòng)到LazyFragment 0的時(shí)候,就會(huì)重建!

所以當(dāng)我們還在思考如何針對(duì)ViewPager的預(yù)加載機(jī)制做懶加載操作時(shí),請(qǐng)將項(xiàng)目中的ViewPager遷移至ViewPager2

附錄:

當(dāng)你的項(xiàng)目中還在使用ViewPager時(shí),建議使用當(dāng)前這個(gè)懶加載框架

abstract class BaseLazyFragment<VM : ViewModel, VB : ViewBinding> : Fragment() {
    private lateinit var viewModel: VM
    private lateinit var binding: VB

    private var isShow = false
    private var isViewCreated = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel = getViewModelInstance()
        binding = getLayoutInflate(layoutInflater)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return binding.root
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initView()
        isViewCreated = true
        lazyLoad()
    }
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        if (isVisibleToUser) {
            isShow = true
            lazyLoad()
        } else {
            isShow = false
        }
    }
    override fun onDestroy() {
        super.onDestroy()
        isShow = false
        isViewCreated = false
    }
    private fun lazyLoad() {
        if (isShow && isViewCreated) {
            initData()
        }
    }
    open fun initData() {}
    open fun initView() {}
    abstract fun getViewModelInstance(): VM
    abstract fun getLayoutInflate(layoutInflater: LayoutInflater): VB
}

使用方式:

class LazyFragment(val index:Int) : BaseLazyFragment<MainVM,FragmentLazy2Binding>() {
    override fun initData() {
        super.initData()
        Log.e("TAG","LazyFragment $index initData -- ")
    }
    override fun getViewModelInstance(): MainVM {
        return MainVM()
    }
    override fun getLayoutInflate(layoutInflater: LayoutInflater): FragmentLazy2Binding {
        return FragmentLazy2Binding.inflate(layoutInflater)
    }
}

到此這篇關(guān)于Android性能優(yōu)化之ViewPagers + Fragment緩存優(yōu)化的文章就介紹到這了,更多相關(guān)Android 緩存優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android 調(diào)用WCF實(shí)例詳解

    Android 調(diào)用WCF實(shí)例詳解

    這篇文章主要介紹了Android 調(diào)用WCF實(shí)例詳解的相關(guān)資料,這里提供了實(shí)例代碼及實(shí)現(xiàn)效果圖,需要的朋友可以參考下
    2016-11-11
  • Android 5秒學(xué)會(huì)使用手勢(shì)解鎖功能

    Android 5秒學(xué)會(huì)使用手勢(shì)解鎖功能

    本文講述的是一個(gè)手勢(shì)解鎖的庫(kù),可以定制顯示隱藏宮格點(diǎn)、路徑、并且?guī)в行【艑m格顯示圖,和震動(dòng)!讓你學(xué)會(huì)使用這個(gè)簡(jiǎn)單,高效的庫(kù),好了,具體內(nèi)容詳情大家通過(guò)本文學(xué)習(xí)吧
    2017-12-12
  • Android RxJava創(chuàng)建操作符Interval

    Android RxJava創(chuàng)建操作符Interval

    這篇文章主要為大家詳細(xì)介紹了Android RxJava創(chuàng)建操作符Interval的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Handler實(shí)現(xiàn)倒計(jì)時(shí)功能

    Handler實(shí)現(xiàn)倒計(jì)時(shí)功能

    這篇文章主要為大家詳細(xì)介紹了Handler實(shí)現(xiàn)倒計(jì)時(shí)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • Android圖片處理:識(shí)別圖像方向并顯示實(shí)例教程

    Android圖片處理:識(shí)別圖像方向并顯示實(shí)例教程

    在Android中使用ImageView顯示圖片的時(shí)候發(fā)現(xiàn)圖片顯示不正,方向偏了或者倒過(guò)來(lái)了,下面與大家分享下具體的解決方法,感性的朋友可以參考下
    2013-06-06
  • Android實(shí)現(xiàn)懸浮可拖拽的Button

    Android實(shí)現(xiàn)懸浮可拖拽的Button

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)懸浮可拖拽的Button,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • Android 快速搭建FTP服務(wù)器的方法

    Android 快速搭建FTP服務(wù)器的方法

    這篇文章主要介紹了Android如何搭建FTP服務(wù)器,需要的朋友可以參考下
    2017-08-08
  • Android組件之BroadcastReceiver廣播接收者

    Android組件之BroadcastReceiver廣播接收者

    這篇文章主要為大家介紹了Android組件之BroadcastReceiver廣播接收者實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • MobLink Android端業(yè)務(wù)場(chǎng)景簡(jiǎn)單說(shuō)明

    MobLink Android端業(yè)務(wù)場(chǎng)景簡(jiǎn)單說(shuō)明

    這篇文章主要介紹了MobLink Android端業(yè)務(wù)場(chǎng)景簡(jiǎn)單說(shuō)明,MobLink的功能實(shí)現(xiàn)就是在分享前會(huì)將鏈接的參數(shù)信息保存到服務(wù)器,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-09-09
  • Android 實(shí)現(xiàn)桌面未讀角標(biāo)

    Android 實(shí)現(xiàn)桌面未讀角標(biāo)

    本文主要介紹了Android實(shí)現(xiàn)桌面未讀角標(biāo)的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-04-04

最新評(píng)論