您的位置:首页 > 其它

getSupportFragmentManager().getFragments() 抛出空指针异常

2016-02-17 16:46 519 查看
背景很简单,在一个FragmentActivity上显示我想要的fragment。

每次显示Fragment的时候我都调用一个函数:

public static boolean showFragmentInActivity(SdkFragment frag, String tag, SdkActivity actv) {
if (frag == null || actv == null || actv.getSupportFragmentManager() == null) {
return false;
}
FragmentTransaction transaction = actv.getSupportFragmentManager().beginTransaction();
if (transaction == null) {
return false;
}
List<Fragment> fragments = actv.getSupportFragmentManager().getFragments();
for (int i = 0; fragments != null && i < fragments.size(); i++) {
transaction.remove(fragments.get(i));
}
transaction.add(frag, tag);
transaction.commitAllowingStateLoss();
return true;
}


该函数是找到该Activity上所有的Fragments,移除这些Fragments,然后加入我要显示的Fragment,将事务提交。

crash重现步骤:

在一个FragmentActivity上我先是显示了两个DialogFragment(标识为A和B,直接采用DialogFragment.show(…)方法),然后我将A和B都dismiss掉,显示另一个DialogFragment(标识为C,调用上述showFragmentInActivity的方法),然后我再dismiss掉C,显示另一个DialogFragment(标识为D,调用上述showFragmentInActivity的方法),此时抛出了如下的异常:



该错误是因为FragmentTransaction的add、remove、detach、attach函数如果传入的参数为null的话,在将事务提交的话,会抛出该异常。

在上述的函数中,我对传入的Fragment已经做过判空检查,所以add函数的参数不可能为空,只可能为remove函数的参数为空。remove的参数我是从getSupportFragmentManager().getFragments()中获取的,怎么可能为空呢。

查看了下getFragments的源代码:

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


从上述代码中看出mActive是用来存当前活跃(Active)的fragment的列表。

我又找到两段代码:

void makeActive(Fragment f) {
if (f.mIndex >= 0) {
return;
}

if (mAvailIndices == null || mAvailIndices.size() <= 0) {
if (mActive == null) {
mActive = new ArrayList<Fragment>();
}
f.setIndex(mActive.size(), mParent);
mActive.add(f);

} else {
f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
mActive.set(f.mIndex, f);
}
if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
}

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.invalidateSupportFragment(f.mWho);
f.initState();
}


这两个函数是源代码内部调用的,我猜想makeActive函数应该是当一个fragment处于active的时候,将该fragment加入该列表中。如果一个Fragment不处于Active状态的时候,将该fragment所在的位置置为空。

非常重要的一点是,我在源代码中没有找到任何一处调用mActive.remove(…),只有mActive.add(…),这说明该列表只有加入,没有删除,只是置为空而已。所以难怪调用getFragments()函数返回的时候,可能存在空的元素(ArrayList是允许空的元素存在的)

解决办法就是在你从fragments中取出的时候,做一个判空就好了。

for (int i = 0; fragments != null && i < fragments.size(); i++) {
/* 这里遇到一个exception,获取fragments的时候,返回的size为2,但是第二个fragment为空
* 如果remove、add、detach、attach方法的参数为空,则会抛出如下的异常:
* java.lang.NullPointerException
* at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:591).....
*/
if (fragments.get(i) != null) {
transaction.remove(fragments.get(i));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  异常 getFragmen