android - fragment 列表和 BackStackEntry 动态

标签 android android-fragments

下面是我为了理解 fragment 处理而编写的一段测试代码。第一个输出是记录 fragment 列表。有2个:GameMenuFragment和Game1Fragment0。 然后记录返回堆栈。它包含 Game1Fragment0。 然后弹出返回堆栈。所以然后返回堆栈日志显示它什么都没有。 布埃诺。 但是现在,再次遍历 fragment 列表,而 size() 仍然返回 2,它在 NPE 上崩溃,因为(显然)Game1Fragment0 不存在。
因此,显然,弹出返回堆栈已从 fragment 列表中删除该 fragment ,但大小仍为 2。 谁能解释一下?

输出:
Game1Fragment(1617): fragment 列表大小:2
Game1Fragment(1617): fragmentList: 2131492865 :GameMenuFragment
Game1Fragment(1617): fragmentList: 2131492865 :Game1Fragment0
Game1Fragment(1617):getBackStackEntryCount:1(从 0 开始)
Game1Fragment(1617): BackStackEntry: Game1Fragment0
Game1Fragment(1617):getBackStackEntryCount2:0(基于 0)
Game1Fragment(1617): fragmentList2 大小:2
Game1Fragment(1617): fragmentList2: 2131492865 : GameMenuFragment
AndroidRuntime(1617):致命异常:main
安卓运行时(1617):java.lang.NullPointerException

FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();

List<Fragment> fragmentList = fragmentManager.getFragments();
Log.w("Game1Fragment", "fragmentList size: " + fragmentList.size());
for (Fragment fragment : fragmentList) {
    Log.w("Game1Fragment", "fragmentList: " + fragment.getId() + " : "+ fragment.getTag());
}

Log.w("Game1Fragment", "getBackStackEntryCount: " + fragmentManager.getBackStackEntryCount() + " (0-based)");
for(int entry = 0; entry < fragmentManager.getBackStackEntryCount(); entry++){
    Log.w("Game1Fragment", "BackStackEntry: " + fragmentManager.getBackStackEntryAt(entry).getName());
}

fragmentManager.popBackStackImmediate(); // pop Game1Fragment0

Log.w("Game1Fragment", "getBackStackEntryCount2: " + fragmentManager.getBackStackEntryCount() + " (0-based)");
for(int entry = 0; entry < fragmentManager.getBackStackEntryCount(); entry++){
    Log.w("Game1Fragment", "BackStackEntry: " + fragmentManager.getBackStackEntryAt(entry).getName());
}

List<Fragment> fragmentList2 = fragmentManager.getFragments();
Log.w("Game1Fragment", "fragmentList2 size: " + fragmentList2.size());
for (Fragment fragment : fragmentList2) {
    Log.w("Game1Fragment", "fragmentList2: " + fragment.getId() + " : "+ fragment.getTag()); // throws NPE on 2nd time through loop
}

最佳答案

Fragment创建后,在 Activity Fragment 中维护对它的引用ArrayList<Fragment> 类型的数组.索引分配给 Fragment实例,它是保存引用的数组元素的索引。

现在 Fragment被销毁,引用应从 ArrayList<Fragment> 中删除.如果引用 Fragment 的元素从 ArrayList 中删除, ArrayList 内的其他元素可能会重新定位(例如,如果您删除第 0 个元素,第 1 个元素现在将成为第 0 个元素)。这将使索引保持在Fragments内。实例无效。因此,该元素不会从 ArrayList 中销毁,而是将 null 分配给该索引。

这是 code哪个处理它。看行mActive.set(f.mIndex, null);

void makeInactive(Fragment f) {
    if (f.mIndex < 0) {
        return;
    }

    if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
    mActive.set(f.mIndex, null);
    if (mAvailIndices == null) {
        mAvailIndices = new ArrayList<Integer>();
    }
    mAvailIndices.add(f.mIndex);
    mActivity.invalidateFragment(f.mWho);
    f.initState();
}

要跟踪已发布的索引,ArrayList<Integer> mAvailIndices被维护,将在为新创建的 Fragments 分配索引时使用 future 。

这里是getFraments的代码返回 mActive 的方法:

@Override
public List<Fragment> getFragments() {
    return mActive;
}

第二次调用fragmentManager.getFragments() ,该列表包含已发布索引的 null。因此,我们应该始终对 Fragment 进行空检查。使用前的实例。

从返回堆栈中弹出将反转事务。如果它被添加到交易中,那么它将被删除并进一步销毁。 这是我编写的示例应用程序的调用堆栈:

MainActivity$Fragment2.onDestroy() line: 53 
MainActivity$Fragment2(Fragment).performDestroy() line: 1912    
FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 1008    
FragmentManagerImpl.removeFragment(Fragment, int, int) line: 1162   
BackStackRecord.popFromBackStack(boolean) line: 714 

关于android - fragment 列表和 BackStackEntry 动态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23155827/

相关文章:

android - 仅限手机(iPhone 和 Android)的 css

android - Robolectric 不支持 API 级别 28

java - 如何在android中设置一个主要 Activity 并填充 fragment

Android fragment 过渡

android - 在 Raspberry-Pi 上实现 Android

java - 如何访问按钮的 protected 字段?

Android:在 viewpager fragment 之间传递数据的最佳方法

java - fragment 不会在 main_activity() 中被替换

android - 检测OSMDroid map 加载完成

Android从另一个 fragment 获取编辑文本值的最简单方法