Android fragments onDestroyView()上带有FragmentStateAdapter的ViewPager2中的片段泄漏
仅供参考:问题很简短,但以防万一,我在结尾添加了更多可能相关的信息。 我需要一个无限滚动的ViewPager2,我想重用项目中的一个片段,因为它已经设计好了,调用已经在viewLifeCycle中建立好了。。 我还知道VP回收屏幕外的片段(显示片段的1个偏移位置),并且在任何给定时刻至少有3个片段,因此使用片段是一种选择 问题是,当转到第四页时,ViewPager2尝试删除第一个片段(如预期的那样),LeakCanary向我显示了这一点(最后显示了整个诊断): 诊断从不指向我的参考文献,只指向android库参考文献。 在代码吼叫之前,我有更多的行,但我一直在修剪它们,直到保持最低限度,泄漏仍然存在Android fragments onDestroyView()上带有FragmentStateAdapter的ViewPager2中的片段泄漏,android-fragments,view,memory-leaks,android-viewpager2,android-ondestroy,Android Fragments,View,Memory Leaks,Android Viewpager2,Android Ondestroy,仅供参考:问题很简短,但以防万一,我在结尾添加了更多可能相关的信息。 我需要一个无限滚动的ViewPager2,我想重用项目中的一个片段,因为它已经设计好了,调用已经在viewLifeCycle中建立好了。。 我还知道VP回收屏幕外的片段(显示片段的1个偏移位置),并且在任何给定时刻至少有3个片段,因此使用片段是一种选择 问题是,当转到第四页时,ViewPager2尝试删除第一个片段(如预期的那样),LeakCanary向我显示了这一点(最后显示了整个诊断): 诊断从不指向我的参考文献,只指向a
// ----- onViewCreated() ------
MyPagerAdapter mPa = new MyPagerAdapter(
getChildFragmentManager(),
getViewLifecycleOwner().getLifecycle()
);
vp.setAdapter(mPa);
扩展FragmentStateAdapter的MyPagerAdapter.class:
@NonNull
@Override
public Fragment createFragment(int position) {
return new SearchPageFragment2(); //Test Fragment
}
@Override
public int getItemCount() {
return 8; //Test fixed number
}
泄漏的碎片:
public class SearchPageFragment2 extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return FragmentSearchPageBinding.inflate(inflater).getRoot();
}
}
是什么导致内存泄漏
问题到此结束。
序言…
主视图(泄漏发生时显示的最远的片段)是一个BackbackEntry,我们从主片段导航到它,该视图包含一个包含应用程序主要信息的工具栏,下面的工具栏是该视图的主要内容,一个固定大小的ViewPager2,有3个片段,在第一个片段上。。。我创建的“可变框架布局”:
private final MutableFrameLayoutAdapter<ElementDBLoaderViewModel.FrameActions> adapter = new MutableFrameLayoutAdapter<>(
this, //Fragment owner
this::getChildFragmentManager, //FragmentManager supplier
() -> ElementDBLoaderViewModel.FrameActions.initiating, //initialValue
action -> { //Function<X, Fragment>
switch (action) {
case crossed:
return new AddElementExpandedFragment();
case not_crossed:
return new AddElementFragment();
case explore:
return new MainDBPaginationFragment2();
}
return null;
}
);
该部件是防漏的,在不同情况下需要数小时的测试
该部件的主要“发动机”:
if (oldFragment != null) {
FragmentTransaction ft = stackFm.beginTransaction();
ft.remove(oldFragment);
addCommit(ft, newFragment);
}
private void addCommit(FragmentTransaction ft, Fragment newFragment) {
fragmentCreated.get().fragmentCreated(newFragment); //stateless adapter interface reference
ft.add(getId(), newFragment);
ft.commit();
}
其中,“stackFm”是在构造函数中使用childFragmentManager.get()
(“this::getChildFragmentManager
”)获得FragmentManager供应商的结果
if (oldFragment != null) {
FragmentTransaction ft = stackFm.beginTransaction();
ft.remove(oldFragment);
addCommit(ft, newFragment);
}
private void addCommit(FragmentTransaction ft, Fragment newFragment) {
fragmentCreated.get().fragmentCreated(newFragment); //stateless adapter interface reference
ft.add(getId(), newFragment);
ft.commit();
}
if (oldFragment != null) {
FragmentTransaction ft = stackFm.beginTransaction();
ft.remove(oldFragment);
addCommit(ft, newFragment);
}
private void addCommit(FragmentTransaction ft, Fragment newFragment) {
fragmentCreated.get().fragmentCreated(newFragment); //stateless adapter interface reference
ft.add(getId(), newFragment);
ft.commit();
}
这个想法是要有一个简单易用的组件,没有任何花哨和直截了当的东西
基本上,这个可变框架布局所在的固定大小的ViewPager2的第一页(片段)可以采用3个不同片段的形式(取决于数据库大小)
泄漏的ViewPager2位于maindPaginationFragment2.class
内,但在到达maindPaginationFragment2片段之前,我们必须先查看addelementExpandedFragment2.class
泄漏诊断(没有我的参考资料)