我有一个类似的问题,我使用过ViewPager2
,并且需要使用,
getChildFragmentManager()
而不是getSupportFragmentManager()
因为我希望 PageFragment 引用父片段(承载ViewPager
)requireParentFragment()
注意当我使用时getSupportFragmentManager()
,我得到了java.lang.IllegalStateException Fragment PageFragment{f152edf} (af30cf2b-acf1-4930-9b83-03ac8144cfc6) f49} is not a child Fragment
我getChildFragmentManager()
使用. ViewPager
_getSupportFragmentManager()
这是 LeakCanary 日志
2020-09-15 05:39:33.461 9611-9689/.... D/LeakCanary: ┬───
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ GC Root: Local variable in native code
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: ├─ android.os.HandlerThread instance
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Leaking: NO (PathClassLoader↓ is not leaking)
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Thread name: 'LeakCanary-Heap-Dump'
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ↓ HandlerThread.contextClassLoader
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never leaking)
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ↓ PathClassLoader.runtimeInternalObjects
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: ├─ java.lang.Object[] array
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Leaking: NO (InternalLeakCanary↓ is not leaking)
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ↓ Object[].[597]
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: ├─ leakcanary.internal.InternalLeakCanary class
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Leaking: NO (MainActivity↓ is not leaking and a class is never leaking)
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ↓ static InternalLeakCanary.resumedActivity
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: ├─ .....ui.MainActivity instance
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Leaking: NO (Activity#mDestroyed is false)
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ↓ MainActivity.mLifecycleRegistry
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ~~~~~~~~~~~~~~~~~~
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: ├─ androidx.lifecycle.LifecycleRegistry instance
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Leaking: UNKNOWN
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ↓ LifecycleRegistry.mObserverMap
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ ~~~~~~~~~~~~
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: ├─ androidx.arch.core.internal.FastSafeIterableMap instance
2020-09-15 05:39:33.462 9611-9689/.... D/LeakCanary: │ Leaking: UNKNOWN
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ↓ FastSafeIterableMap.mHashMap
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ~~~~~~~~
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: ├─ java.util.HashMap instance
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ Leaking: UNKNOWN
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ↓ HashMap.table
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ~~~~~
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: ├─ java.util.HashMap$Node[] array
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ Leaking: UNKNOWN
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ↓ HashMap$Node[].[5]
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ~~~
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: ├─ java.util.HashMap$Node instance
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ Leaking: UNKNOWN
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ↓ HashMap$Node.key
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ~~~
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: ├─ androidx.viewpager2.adapter.FragmentStateAdapter$FragmentMaxLifecycleEnforcer$3 instance
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ Leaking: UNKNOWN
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ Anonymous class implementing androidx.lifecycle.LifecycleEventObserver
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ↓ FragmentStateAdapter$FragmentMaxLifecycleEnforcer$3.this$1
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ~~~~~~
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: ├─ androidx.viewpager2.adapter.FragmentStateAdapter$FragmentMaxLifecycleEnforcer instance
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ Leaking: UNKNOWN
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ↓ FragmentStateAdapter$FragmentMaxLifecycleEnforcer.mViewPager
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: │ ~~~~~~~~~~
2020-09-15 05:39:33.463 9611-9689/.... D/LeakCanary: ├─ androidx.viewpager2.widget.ViewPager2 instance
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ Leaking: YES (View detached and has parent)
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ mContext instance of .....ui.MainActivity with mDestroyed = false
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ View#mParent is set
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ View#mAttachInfo is null (view detached)
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ View.mID = R.id.viewpager
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ View.mWindowAttachCount = 1
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ ↓ ViewPager2.mParent
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: ├─ androidx.coordinatorlayout.widget.CoordinatorLayout instance
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ Leaking: YES (ViewPager2↑ is leaking and View detached and has parent)
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ mContext instance of .....ui.MainActivity with mDestroyed = false
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ View#mParent is set
2020-09-15 05:39:33.465 9611-9689/.... D/LeakCanary: │ View#mAttachInfo is null (view detached)
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: │ View.mWindowAttachCount = 1
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: │ ↓ CoordinatorLayout.mParent
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: ╰→ androidx.drawerlayout.widget.DrawerLayout instance
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because .....ui.fragments.ReadFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: key = e3b96092-06d5-48ae-93bf-b38680cc0c35
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: watchDurationMillis = 6413
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: retainedDurationMillis = 1400
2020-09-15 05:39:33.466 9611-9689/.... D/LeakCanary: mContext instance of .....ui.MainActivity with mDestroyed = false
2020-09-15 05:39:33.467 9611-9689/.... D/LeakCanary: View#mParent is null
2020-09-15 05:39:33.467 9611-9689/.... D/LeakCanary: View#mAttachInfo is null (view detached)
2020-09-15 05:39:33.467 9611-9689/.... D/LeakCanary: View.mID = R.id.drawer_layout
所以,为了解决这个问题,我清除了所有已关闭的子片段ViewPager
;为此,我必须注册所有片段 ID,并覆盖containsItem()
以清除它们,如下所示:
public class PageFragmentPagerAdapter extends FragmentStateAdapter {
private FragmentManager mFragmentMgr;
private List<Integer> currentPageIds = new ArrayList<>();
public PageFragmentPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
mFragmentMgr = fragmentManager;
}
@NonNull
@Override
public Fragment createFragment(int position) {
PageFragment pageFragment = PageFragment.newInstance(position);
currentPageIds.add(position);
return pageFragment;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return N_PAGES;
}
@Override
public boolean containsItem(long itemId) {
for (Integer id : currentPageIds)
if (id == itemId) {
currentPageIds.remove(Integer.valueOf(String.valueOf(itemId)));
clearFragment(id);
break;
}
return super.containsItem(itemId);
}
private void clearFragment(int fragmentId) {
FragmentTransaction transaction = mFragmentMgr.beginTransaction();
PageFragment fragment = (PageFragment) mFragmentMgr.findFragmentByTag("f" + fragmentId);
if (fragment != null) {
transaction.remove(fragment);
}
transaction.commitAllowingStateLoss();
}
}
第二件事不要使用ViewPager
Activity 的生命周期来实例化适配器requireActivity().getLifecycle()
,而是使用其片段的生命周期,getViewLifecycleOwner().getLifecycle()
如下所示
PageFragmentPagerAdapter mPagerAdapter = new PageFragmentPagerAdapter(
getChildFragmentManager(), getViewLifecycleOwner().getLifecycle());