片段列表和BackStackEntry动态

Al *_*ath 2 android android-fragments

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

输出:
Game1Fragment(1617):fragmentList size:2
Game1Fragment(1617):fragmentList:2131492865:GameMenuFragment
Game1Fragment(1617):fragmentList:2131492865:Game1Fragment0
Game1Fragment(1617):getBackStackEntryCount:1(0-based)
Game1Fragment(1617):BackStackEntry :Game1Fragment0
Game1Fragment(1617):getBackStackEntryCount2:0(基于0)
Game1Fragment(1617):fragmentList2大小:2
Game1Fragment(1617):fragmentList2:2131492865:GameMenuFragment
AndroidRuntime(1617):FATAL EXCEPTION:main
AndroidRuntime(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
}
Run Code Online (Sandbox Code Playgroud)

Man*_*ani 7

Fragment被创建,参考被保持它的活性在Fragment阵列的类型的ArrayList<Fragment>.将索引分配给Fragment实例,该实例是保留引用的数组元素的索引.

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

这是处理它的代码.看看线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();
}
Run Code Online (Sandbox Code Playgroud)

保持跟踪已发布的索引,ArrayList<Integer> mAvailIndices将在将索引分配给Fragments将来新创建时使用.

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

@Override
public List<Fragment> getFragments() {
    return mActive;
}
Run Code Online (Sandbox Code Playgroud)

第二次调用时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 
Run Code Online (Sandbox Code Playgroud)