前段時(shí)間在給公司項(xiàng)目做優(yōu)化,換用了ViewPager盒粮,可以左右切換頁面鸵鸥,交互更順滑,改完之后發(fā)現(xiàn)Fragment總是不復(fù)用,每次切換回來會(huì)重復(fù)走onCreateView()
和onDestroyView()
生命周期妒穴?宋税??這咋能行呢讼油,于是就在onCreateView()
做了簡單的判斷杰赛,因?yàn)轫?xiàng)目用的是ViewBinding,所以就ViewBinding不為空就直接返回ViewBinding.getRoot()
了矮台。這幾天在看Android Jetpack的ViewPager2發(fā)現(xiàn)多了個(gè)FragmentStateAdapter
用法比之前簡單不少:
class CollectionDemoFragment : Fragment() {
// When requested, this adapter returns a DemoObjectFragment,
// representing an object in the collection.
private lateinit var demoCollectionAdapter: DemoCollectionAdapter
private lateinit var viewPager: ViewPager2
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.collection_demo, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
demoCollectionAdapter = DemoCollectionAdapter(this)
viewPager = view.findViewById(R.id.pager)
viewPager.adapter = demoCollectionAdapter
}
}
//重點(diǎn)在這里 就重寫了兩個(gè)方法
class DemoCollectionAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = 100
override fun createFragment(position: Int): Fragment {
// Return a NEW fragment instance in createFragment(int)
val fragment = DemoObjectFragment()
fragment.arguments = Bundle().apply {
// Our object is just an integer :-P
putInt(ARG_OBJECT, position + 1)
}
return fragment
}
}
然后興沖沖的給項(xiàng)目安排上乏屯,感覺自己又跟上大佬的腳步了,可是無意間看到居然沒有重寫走onCreateView()
和onDestroyView()
生命周期(順便提一下FragmentManager.FragmentLifecycleCallbacks
可以監(jiān)控Fragment生命周期類似Activity生命周期監(jiān)聽Application.ActivityLifecycleCallbacks
)瘦赫,本著打破砂鍋問到底的原則詳細(xì)了解了下FragmentPagerAdapter辰晕、FragmentStatePagerAdapter和FragmentStateAdapter三者的區(qū)別。
FragmentPagerAdapter
源于androidx.fragment确虱,繼承于PagerAdapter
含友,已于androidx.fragment 1.3.0版本廢棄,重點(diǎn)在instantiateItem()
@Override
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?
//這個(gè)fragment已經(jīng)存在過?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
//已經(jīng)存在執(zhí)行attach(fragment);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {//沒有存在通過getItem()獲取
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 {
fragment.setUserVisibleHint(false);
}
}
return fragment;
}
可以看到FragmentPagerAdapter
的處理邏輯是存在這個(gè)Fragment就會(huì)執(zhí)行attach()
必然會(huì)重走一遍Fragment的生命周期校辩,并不會(huì)復(fù)用之前創(chuàng)建的Fragment窘问,顯然跟我們要的不符,這個(gè)時(shí)候我們就用到了FragmentStatePagerAdapter
FragmentStatePagerAdapter
同樣源于androidx.fragment召川,繼承于PagerAdapter
南缓,已于androidx.fragment 1.3.0版本廢棄,同樣我們也看一下instantiateItem()
里的實(shí)現(xiàn)
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
fragment.setUserVisibleHint(false);
}
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
}
return fragment;
}
可以看到FragmentStatePagerAdapter
有緩存Fragment隊(duì)列荧呐,當(dāng)Fragment實(shí)例化之后會(huì)取已經(jīng)實(shí)例化的Fragment汉形,并且多了個(gè)SavedState的邏輯,用于保存Fragment的狀態(tài)(滑過后會(huì)保存當(dāng)前界面倍阐,以及下一個(gè)界面和上一個(gè)界面(如果有)概疆,最多保存3個(gè),其他會(huì)被銷毀掉峰搪,可以通過ViewPager的setOffscreenPageLimit(int limit)
設(shè)置)
但在回調(diào)onDestroy()
方法之前會(huì)回調(diào)onSaveInstanceState(Bundle outState)
方法來保存Fragment的狀態(tài)岔冀,下次Fragment顯示時(shí)通過onCreate(Bundle savedInstanceState)
把存儲(chǔ)的狀態(tài)值取出來,FragmentStatePagerAdapter
比較適合頁面比較多的情況概耻。
FragmentStateAdapter
源于ViewPager2是FragmentPagerAdapter
和FragmentStatePagerAdapter
的替換類使套,繼承于RecyclerView.Adapter
,
與FragmentStatePagerAdapter
相似鞠柄,該適配器實(shí)現(xiàn)了StatefulAdapter
用于保存Fragment的狀態(tài)侦高。
private void ensureFragment(int position) {
long itemId = getItemId(position);
if (!mFragments.containsKey(itemId)) {
// TODO(133419201): check if a Fragment provided here is a new Fragment
Fragment newFragment = createFragment(position);
newFragment.setInitialSavedState(mSavedStates.get(itemId));
mFragments.put(itemId, newFragment);
}
}
可以看到FragmentStateAdapter
同樣有緩存Fragment隊(duì)列