判断当前界面是该fragment_学不动也要学!探究Fragment延迟加载的前世今生
碼個(gè)蛋(codeegg)?第?852?次推文
作者:一包純牛奶鏈接:https://juejin.im/post/5e085dafe51d45580769a1eb
碼妞看世界
大家普遍對(duì)于Fragment懶加載的問(wèn)題比較關(guān)心,其實(shí),對(duì)于Fragment懶加載問(wèn)題的處理由來(lái)已久,網(wǎng)上不乏相關(guān)的優(yōu)秀文章。但是,由于Fragment生命周期的原因使得懶加載問(wèn)題的處理并不是那么的優(yōu)雅。顯然,Google也意識(shí)到了問(wèn)題所在。
因此,在Androidx的庫(kù)中對(duì)于Fragment的生命周期狀態(tài)的控制進(jìn)行了深度優(yōu)化,使得我們更容易的去管控Fragment的生命周期,也使得我們更容易的去處理懶加載問(wèn)題。但是,前提條件是我們要了解Google對(duì)于Fragment做了哪些優(yōu)化。那么就讓我們借此機(jī)會(huì)一起來(lái)探究一下吧!( 懶加載稱作延遲加載我覺(jué)得更貼切一些,所以下文就統(tǒng)稱為延遲加載了。 )
一、Fragment延遲加載的前世
雖然本篇文章是對(duì)于Fragment新特性的探究,但是我覺(jué)得寫文章總要有個(gè)因果。也為了照顧一下還不太了解什么是延遲加載的同學(xué)。我們還是先來(lái)了解一下延遲加載,順便回顧一下Fragment延遲加載的舊方案。
1. 為什么要對(duì)Fragment做延遲加載?
首先,我們要搞清楚一個(gè)問(wèn)題。“Fragment延遲加載“中的“延遲”并不指的是延遲加載Fragment,而是延遲加載Fragment中的數(shù)據(jù)。對(duì)于Fragment的使用通常我們會(huì)結(jié)合ViewPager,ViewPager會(huì)默認(rèn)在當(dāng)前頁(yè)面的左右兩邊至少預(yù)加載一個(gè)頁(yè)面以保證ViewPager的流暢性。
我們假設(shè)在ViewPager的所有Fragment中都存在網(wǎng)絡(luò)請(qǐng)求,當(dāng)我們打開(kāi)這個(gè)頁(yè)面的時(shí)候由于ViewPager的預(yù)加載原因,即使在其它Fragment不可見(jiàn)的情況下也會(huì)去進(jìn)行網(wǎng)絡(luò)請(qǐng)求加載數(shù)據(jù)。而如果此時(shí)用戶根本就沒(méi)有去滑動(dòng)ViewPager就退出了應(yīng)用或者切換到了其他頁(yè)面。那么對(duì)于這個(gè)不可見(jiàn)的Fragment中的網(wǎng)絡(luò)請(qǐng)求豈不是既浪費(fèi)了流量也浪費(fèi)了手機(jī)和服務(wù)器的性能?
那么此時(shí)有的同學(xué)就有問(wèn)題了。你就不能在Fragment顯示的時(shí)候去加載數(shù)據(jù)嗎?
問(wèn)的好!在解答之前我們先來(lái)看下Fragment的生命周期。
想必這張圖大家應(yīng)該都非常熟悉了。
當(dāng)Fragment被預(yù)加載的時(shí)候,此Fragment的生命周期會(huì)從onAttach執(zhí)行到onResume。顯然我們無(wú)法通過(guò)Fragment的生命周期來(lái)控制Fragment的延遲加載。
那么該怎么辦呢?我們且往下看。
2. 如何處理Fragment的延遲加載?
通過(guò)上一小節(jié)的分析我們知道想要在Fragment的生命周期中處理延遲加載的問(wèn)題顯然是走不通的。所以想要處理Fragment的延遲加載就需要另想它法了。
還好,在Fragment中為我們提供了一個(gè)?setUserVisibleHint(isVisibleToUser: Boolean)?的方法,這個(gè)方法中有一個(gè)?isVisibleToUser?的boolean類型的參數(shù),其意義表示當(dāng)前的Fragment是否對(duì)用戶可見(jiàn)。
因此,對(duì)于Fragment的延遲加載我們便可以通過(guò)這個(gè)方法來(lái)展開(kāi)。既然要使用setUserVisibleHint(isVisibleToUser: Boolean)那么就應(yīng)該知道這個(gè)方法的調(diào)用時(shí)機(jī)。我們寫一個(gè)ViewPager嵌套Fragment的例子來(lái)打印下日志:
注:上圖打印的日志中”position:0“表示當(dāng)前Fragment,“position:1”表示預(yù)加載的Fragment,下同。
可見(jiàn)該方法是在Fragment的onAttach之前就已經(jīng)被調(diào)用了。因此,對(duì)于延遲加載我們可以在setUserVisibleHint(isVisibleToUser: Boolean)方法及onViewCreated(view: View, savedInstanceState: Bundle?)添加標(biāo)志位來(lái)控制是否加載數(shù)據(jù)。我們來(lái)看下代碼:?
abstract class BaseLazyFragment : Fragment() { /** * 當(dāng)前Fragment狀態(tài)是否可見(jiàn) */ private var isVisibleToUser: Boolean = false /** * 是否已創(chuàng)建View */ private var isViewCreated: Boolean = false /** * 是否第一次加載數(shù)據(jù) */ private var isFirstLoad = true override fun setUserVisibleHint(isVisibleToUser: Boolean) { super.setUserVisibleHint(isVisibleToUser) this.isVisibleToUser = isVisibleToUser onLazyLoad() } private fun onLazyLoad() { if (isVisibleToUser && isViewCreated && isFirstLoad) { isFirstLoad = false lazyLoad() } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) isViewCreated = true onLazyLoad() }????protected?abstract?fun?lazyLoad()}我們通過(guò)在Fragment中添加了三個(gè)標(biāo)志位實(shí)現(xiàn)了延遲加載的功能。我們到TestFragment嘗試一下:
class?TestFragment?:?BaseLazyFragment()?{ private var position: Int = 0 override fun setUserVisibleHint(isVisibleToUser: Boolean) { super.setUserVisibleHint(isVisibleToUser) val bundle = arguments position = bundle!!.getInt(KEY_POSITION) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val cardView = CardView(inflater, container) cardView.bind(Card.fromBundle(arguments!!),position) return cardView.view } companion object { private const val KEY_POSITION = "position" fun getInstance(card: Card, position: Int): TestFragment { val fragment = TestFragment() val bundle = card.toBundle() bundle.putInt(KEY_POSITION, position) fragment.arguments = bundle return fragment } } override fun lazyLoad() { showToast("Fragment$position is loading data") } private fun showToast(content: String) { Toast.makeText(context, content, Toast.LENGTH_SHORT).show()????}}我們來(lái)看下效果:
嗯!立竿見(jiàn)影,只有當(dāng)Fragment完全顯示出來(lái)的時(shí)候loading data的操作才被執(zhí)行。這種延遲加載的方案在Androidx 1.1.0版本以前被廣泛應(yīng)用。而在Androidx 1.1.0版本中,Google對(duì)于Fragment進(jìn)行了優(yōu)化處理,使得延遲加載也有了新的解決方案。
二、Fragment的setMaxLifecycle探究
上一節(jié)中我們講到因?yàn)閂iewPager的預(yù)加載機(jī)制以及Fragment的生命周期無(wú)法得以控制,我們不得不通過(guò) setUserVisibleHint(isVisibleToUser: Boolean) 和 onViewCreated(view: View, savedInstanceState: Bundle?) 方法以及添加三個(gè)標(biāo)志位來(lái)處理延遲加載,顯然這樣的代碼并不優(yōu)雅。
當(dāng)我們將Android項(xiàng)目遷移到Androidx 并將 Androidx 版本升級(jí)到1.1.0之后發(fā)現(xiàn),我們第一節(jié)中用到的setUserVisibleHint(isVisibleToUser: Boolean)方法已被標(biāo)記為廢棄了!
/** * ... 省略其它注釋 * @deprecated Use {@link FragmentTransaction#setMaxLifecycle(Fragment, Lifecycle.State)} * instead. */@Deprecatedpublic void setUserVisibleHint(boolean isVisibleToUser) { if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null && isAdded() && mIsCreated) { mFragmentManager.performPendingDeferredStart(this); } mUserVisibleHint = isVisibleToUser; mDeferStart = mState < STARTED && !isVisibleToUser; if (mSavedFragmentState != null) { // Ensure that if the user visible hint is set before the Fragment has // restored its state that we don't lose the new value mSavedUserVisibleHint = isVisibleToUser; }}并且從注釋中可以看到使用 FragmentTransaction#setMaxLifecycle(Fragment, Lifecycle.State)?方法來(lái)替換setUserVisibleHint方法。setMaxLifecycle實(shí)在Androidx 1.1.0中新增加的一個(gè)方法。
setMaxLifecycle從名字上來(lái)看意思是設(shè)置一個(gè)最大的生命周期,因?yàn)檫@個(gè)方法是在 FragmentTransaction 中,因此我們可以知道應(yīng)該是為Fragment來(lái)設(shè)置一個(gè)最大的生命周期。我們來(lái)看下setMaxLifecycle的源碼:
/** * Set a ceiling for the state of an active fragment in this FragmentManager. If fragment is * already above the received state, it will be forced down to the correct state. * *The fragment provided must currently be added to the FragmentManager to have it's
* Lifecycle state capped, or previously added as part of this transaction. The * {@link Lifecycle.State} passed in must at least be {@link Lifecycle.State#CREATED}, otherwise * an {@link IllegalArgumentException} will be thrown. * * @param fragment the fragment to have it's state capped. * @param state the ceiling state for the fragment. * @return the same FragmentTransaction instance */@NonNullpublic FragmentTransaction setMaxLifecycle(@NonNull Fragment fragment, @NonNull Lifecycle.State state) { addOp(new Op(OP_SET_MAX_LIFECYCLE, fragment, state)); return this;}這個(gè)方法接收一個(gè)Fragment參數(shù)和一個(gè)Lifecycle的狀態(tài)參數(shù)。Lifecycle是Jetpack中很重要的一個(gè)庫(kù),它具有對(duì)Activity和Fragment生命周期感知能力,相信很多同學(xué)都應(yīng)該對(duì)Lifecycle都略知一二。
在Lifecycle的State中定義了五種生命周期狀態(tài),如下:
public enum State { /** * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch * any more events. For instance, for an {@link android.app.Activity}, this state is reached * right before Activity's {@link android.app.Activity#onDestroy() onDestroy} call. */ DESTROYED, /** * Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is * the state when it is constructed but has not received * {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet. */ INITIALIZED, /** * Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached in two cases: * * after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call; * right before {@link android.app.Activity#onStop() onStop} call. * */ CREATED, /** * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached in two cases: * * after {@link android.app.Activity#onStart() onStart} call; * right before {@link android.app.Activity#onPause() onPause} call. * */ STARTED, /** * Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached after {@link android.app.Activity#onResume() onResume} is called. */ RESUMED; /** * Compares if this State is greater or equal to the given {@code state}. * * @param state State to compare with * @return true if this State is greater or equal to the given {@code state} */ public boolean isAtLeast(@NonNull State state) { return compareTo(state) >= 0; } }而在?setMaxLifecycle?中接收的生命周期狀態(tài)要求不能低于?CREATED,否則會(huì)拋出一個(gè)?IllegalArgumentException?的異常。當(dāng)傳入?yún)?shù)為DESTROYED或者INITIALIZED時(shí)則會(huì)拋出如下圖的異常:
因此除去這兩個(gè)生命周期外,僅剩下CREATED、STARTED、RESUMED三個(gè)生命周期狀態(tài)的參數(shù)可用,那么接下來(lái)我們就逐個(gè)來(lái)研究這三個(gè)參數(shù)的效果。
1. 不設(shè)置setMaxLifecycle
我們先來(lái)看下在不設(shè)置setMaxLifecycle的時(shí)候添加一個(gè)Fragment的狀態(tài),以便和后邊的情況進(jìn)行對(duì)比。首先我們?cè)贏ctivity中添加一個(gè)Fragment,代碼如下:
fragment = TestLifecycleFragment.getInstance(Card.DECK[0], 0)val fragmentTransaction = supportFragmentManager.beginTransaction()fragmentTransaction.add(R.id.ll_fragment, fragment)fragmentTransaction.commit()啟動(dòng)Activity,我們將該Fragment生命周期的日志打印出來(lái)如下:
可以看到這個(gè)Fragment生命周期從onAttach一直執(zhí)行到了onResume,?并且在Activity中成功顯示出了Fragment
2. setMaxLifecycle與CREATED
接下來(lái),我們將maxLifecycle設(shè)置為CREATED:
fragment = TestLifecycleFragment.getInstance(Card.DECK[0], 0)val fragmentTransaction = supportFragmentManager.beginTransaction()fragmentTransaction.add(R.id.ll_fragment, fragment)fragmentTransaction.setMaxLifecycle(fragment, Lifecycle.State.CREATED)fragmentTransaction.commit()再來(lái)看日志輸出:
可以看到該Fragment的生命周期僅僅執(zhí)行到了onCreate就沒(méi)再往下執(zhí)行了。并且Activity中沒(méi)有加載出來(lái)當(dāng)前Fragment。
那么現(xiàn)在問(wèn)題來(lái)了,假設(shè)Fragment已經(jīng)執(zhí)行到了onResume, 此時(shí)再為Fragment設(shè)置一個(gè)CREATED的最大生命周期會(huì)出現(xiàn)什么樣的情況呢?我們通過(guò)日志來(lái)驗(yàn)證一下:
從日志中可以看到已經(jīng)執(zhí)行了onResume的Fragment,將其最大生命周期設(shè)置為CREATED后會(huì)執(zhí)行onPause->onStop->onDestoryView。也就是回退到了onCreate的狀態(tài)。
3. setMaxLifecycle與STARTED
接下來(lái),我們將maxLifecycle設(shè)置為STARTED:
fragment = TestLifecycleFragment.getInstance(Card.DECK[0], 0)val fragmentTransaction = supportFragmentManager.beginTransaction()fragmentTransaction.add(R.id.ll_fragment, fragment)fragmentTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED)fragmentTransaction.commit()日志輸出如下:
可以看到Fragment的生命周期執(zhí)行到了onStart,并且Activity中成功顯示出了當(dāng)前fragment。
同樣,假設(shè)Fragment已經(jīng)執(zhí)行到了onResume方法再為其設(shè)置最大生命周期為 STARTED 會(huì)怎樣呢?來(lái)看日志:
可以看到,設(shè)置最大生命周期STARTED后Fragment執(zhí)行了onPause方法,也就是生命周期退回到了onStart。
4. setMaxLifecycle與RESUMED
最后,我們將maxLifecycle設(shè)置為RESUMED:
fragment = TestLifecycleFragment.getInstance(Card.DECK[0], 0)val fragmentTransaction = supportFragmentManager.beginTransaction()fragmentTransaction.add(R.id.ll_fragment, fragment)fragmentTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED)fragmentTransaction.commit()可以看到此時(shí)和第一種情況一樣的效果,Fragment的生命周期執(zhí)行到了 onResume。
而對(duì)于已經(jīng)執(zhí)行了onResume后的Fragment,再去設(shè)置最大生命周期為RESUMED會(huì)怎么樣呢?因?yàn)楫?dāng)前Fragment已經(jīng)是RESUMED狀態(tài)了,所以不會(huì)再去執(zhí)行任何代碼。
到這里我們可以得出一個(gè)結(jié)論:
通過(guò)setMaxLifecycle方法可以精確控制Fragment生命周期的狀態(tài),如果Fragment的生命周期狀態(tài)小于被設(shè)置的最大生命周期,則當(dāng)前Fragment的生命周期會(huì)執(zhí)行到被設(shè)置的最大生命周期;
反之,如果Fragment的生命周期狀態(tài)大于被設(shè)置的最大生命周期,那么則會(huì)回退到被設(shè)置的最大生命周期。
有了這一結(jié)論,在ViewPager中便可以對(duì)Fragment的生命周期進(jìn)行控制,以此來(lái)更方便的實(shí)現(xiàn)延遲加載功能了。
三、Fragment延遲加載的今生
1、延遲加載新方案之于ViewPager
通過(guò)上一小節(jié)的分析我們知道了可以通過(guò)setMaxLifecycle來(lái)設(shè)置Fragment的最大生命周期,從而可以實(shí)現(xiàn)ViewPager中Fragment的延遲加載。當(dāng)然,關(guān)于生命周期狀態(tài)處理的操作無(wú)需我們自己實(shí)現(xiàn),在Androidx 1.1.0版本中的FragmentStatePagerAdapter已經(jīng)幫我們實(shí)現(xiàn)了,只需要在使用時(shí)候傳進(jìn)去相應(yīng)的參數(shù)即可。
FragmentStatePagerAdapter的構(gòu)造方法接收兩個(gè)參數(shù),如下:
/** * Constructor for {@link FragmentStatePagerAdapter}. * * If {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} is passed in, then only the current * Fragment is in the {@link Lifecycle.State#RESUMED} state, while all other fragments are * capped at {@link Lifecycle.State#STARTED}. If {@link #BEHAVIOR_SET_USER_VISIBLE_HINT} is * passed, all fragments are in the {@link Lifecycle.State#RESUMED} state and there will be * callbacks to {@link Fragment#setUserVisibleHint(boolean)}. * * @param fm fragment manager that will interact with this adapter * @param behavior determines if only current fragments are in a resumed state */public FragmentStatePagerAdapter(@NonNull FragmentManager fm, @Behavior int behavior) { mFragmentManager = fm; mBehavior = behavior;}第一個(gè)FragmentManager 參數(shù)不必多說(shuō),第二個(gè)參數(shù)時(shí)一個(gè)枚舉類型的Behavior參數(shù),其可選值如下:
@Retention(RetentionPolicy.SOURCE)@IntDef({BEHAVIOR_SET_USER_VISIBLE_HINT, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT})private @interface Behavior { }當(dāng)behavior為BEHAVIOR_SET_USER_VISIBLE_HINT時(shí),Fragment改變的時(shí)候,setUserVisibleHint方法會(huì)被調(diào)用,也就是這個(gè)參數(shù)其實(shí)是為了兼容以前的老代碼。并且BEHAVIOR_SET_USER_VISIBLE_HINT參數(shù)已經(jīng)被置為廢棄。所以我們的可選參數(shù)只剩下了BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT。
當(dāng)behavior為BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT時(shí)意味著只有當(dāng)前顯示的Fragment會(huì)被執(zhí)行到onResume,而其它Fragment的生命周期都只會(huì)執(zhí)行到onStart。
這一功能時(shí)如何實(shí)現(xiàn)的呢?我們追隨BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT的腳步找到了setPrimaryItem方法,這個(gè)方法的作用是設(shè)置ViewPager當(dāng)前顯示的Item,其源碼如下:
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { Fragment fragment = (Fragment)object; if (fragment != mCurrentPrimaryItem) { if (mCurrentPrimaryItem != null) { mCurrentPrimaryItem.setMenuVisibility(false); if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED); } else { mCurrentPrimaryItem.setUserVisibleHint(false); } } fragment.setMenuVisibility(true); if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED); } else { fragment.setUserVisibleHint(true); } mCurrentPrimaryItem = fragment; } }這段代碼非常簡(jiǎn)單易懂,mCurrentPrimaryItem是當(dāng)前正在顯示的item,fragment是接下來(lái)要顯示的item。可以看到當(dāng)mBehavior 為BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT時(shí),mCurrentPrimaryItem的最大生命周期被設(shè)置為了STARTED,而fragment的最大生命周期則被設(shè)置為了RESUMED。
而當(dāng)mBehavior為BEHAVIOR_SET_USER_VISIBLE_HINT時(shí)仍然會(huì)調(diào)用setUserVisibleHint方法,這種情況就不再討論,因?yàn)锽EHAVIOR_SET_USER_VISIBLE_HINT也已經(jīng)被廢棄掉了。 那么我們著重來(lái)分析一下BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT時(shí)的情況:
mCurrentPrimaryItem是當(dāng)前顯示的Fragment,所以該Fragment必然已經(jīng)執(zhí)行到了onResume方法,而此時(shí)為其設(shè)置了最大生命周期STARTED,那么mCurrentPrimaryItem必然會(huì)執(zhí)行onPause退回到STARTED狀態(tài)。 而fragment當(dāng)前生命周期狀態(tài)為onStart,當(dāng)為其設(shè)置了RESUME的最大生命周期狀態(tài)后,fragment必然會(huì)執(zhí)行onResume方法進(jìn)入RESUMED狀態(tài)。
知道了這一結(jié)論后,我們?cè)偃ミM(jìn)行懶加載的控制是不是就異常簡(jiǎn)單了?此時(shí)我們只需要一個(gè)flag去標(biāo)志是否是第一次加載數(shù)據(jù)就可以了。
因此,懶加載的實(shí)現(xiàn)可以如下:
abstract class TestLifecycleFragment : Fragment() { private var isFirstLoad = true override fun onResume() { super.onResume() if (isFirstLoad) { isFirstLoad = false loadData() } } abstract fun loadData()}2、延遲加載之于ViewPager2
(有機(jī)會(huì)專門分享一篇講解ViewPager2的文章。)在分析offScreenPageLimit時(shí)候得出過(guò)這樣一個(gè)結(jié)論:
ViewPager2的offScreenPageLimit默認(rèn)值為OFFSCREEN_PAGE_LIMIT_DEFAULT,當(dāng)setOffscreenPageLimit為OFFSCREEN_PAGE_LIMIT_DEFAULT時(shí)候會(huì)使用RecyclerView的緩存機(jī)制。
默認(rèn)只會(huì)加載當(dāng)前顯示的Fragment,而不會(huì)像ViewPager一樣至少預(yù)加載一個(gè)item。
當(dāng)切換到下一個(gè)item的時(shí)候,當(dāng)前Fragment會(huì)執(zhí)行onPause方法,而下一個(gè)Fragment則會(huì)從onCreate一直執(zhí)行到onResume。當(dāng)再次滑動(dòng)回第一個(gè)頁(yè)面的時(shí)候當(dāng)前頁(yè)面同樣會(huì)執(zhí)行onPuase,而第一個(gè)頁(yè)面會(huì)執(zhí)行onResume。
也就是說(shuō)在ViewPager2中,默認(rèn)關(guān)閉了預(yù)加載機(jī)制。沒(méi)有了預(yù)加載機(jī)制再談延遲加載其實(shí)也沒(méi)有任何意義了。所以關(guān)于ViewPager2的延遲加載也就不用多說(shuō)了吧?
只需要將網(wǎng)絡(luò)請(qǐng)求放到onStart中即可。相信隨著ViewPager2的普及延遲加載的概念也會(huì)慢慢淡出開(kāi)發(fā)者的視線。
2020/1/4補(bǔ)充:
如果為ViewPager2設(shè)置了offScreenPageLimit(1)那結(jié)果會(huì)是怎樣的呢?我們來(lái)看日志:
從日志中可以看到ViewPager2預(yù)加載了一個(gè)Fragment,并且預(yù)加載的Fragment的生命周期僅僅執(zhí)行到了onStart。所以此處我們可以猜測(cè)在FragmentStateAdapter中一定設(shè)置了setMaxLifecycle(fragment, STARTED),具體源碼不再貼出,大家可以自行查看。因此,此時(shí)處理懶加載問(wèn)題其實(shí)和ViewPager的懶加載新方案如出一轍了,僅僅需要添加一個(gè)boolean值即可。
三、總結(jié)
本篇文章對(duì)于Fragment的延遲加載進(jìn)行了深入的探究,并且了解了在Androidx 1.1.0版本中對(duì)Fragment最大生命周期狀態(tài)的控制,從而探究出了Fragment延遲加載的新方案。
對(duì)于ViewPager2,因其默認(rèn)不會(huì)進(jìn)行預(yù)加載因此也就意味著我們無(wú)需處理ViewPager2的延遲加載問(wèn)題。好了,這一篇花費(fèi)了我兩個(gè)周末(其實(shí)是上周末寫了一半偷了個(gè)懶)的文章到此就結(jié)束了,如果你從中學(xué)有所收獲那么請(qǐng)你不要吝嗇留下你的贊。
相關(guān)文章:
Retrofit 用了那么久,動(dòng)態(tài)代理還不明白
2019年互聯(lián)網(wǎng)公司福利縮水指南
再見(jiàn)2019!你好2020!
今日問(wèn)題:
Fragment用得溜嘛?
專屬升級(jí)社區(qū):《這件事情,我終于想明白了》?
總結(jié)
以上是生活随笔為你收集整理的判断当前界面是该fragment_学不动也要学!探究Fragment延迟加载的前世今生的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: kvm虚拟机设置万兆网卡_SR-IOV
- 下一篇: tcpdump抓包ftp协议_tcpdu