下面是我为了理解 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/