天天看点

关于Fragment的IllegalStateException的部分经验

项目上线以后,总是要看Bugly上的崩溃统计。最近发现有一个

 java.lang.IllegalStateException 

  Fragment already added:

连续出现了很多次。看了Bugly上的崩溃提示,

1. 该异常表示fragment已经被添加过,通常是因为重复添加fragment导致的,建议调用FragmentTransaction.add方法,先判断fragment.isAdded()。
[解决方案]:以下是参考解决方案:
if (fragment.isAdded()) { 
    fragmentManager.beginTransaction().show(fragment).commit();
} else {
    fragmentManager.beginTransaction().remove(fragment).commit();
    frament = new Fragment();
    fragmentManager.beginTransaction().add(R.id.layout_frame, fragment).commit();
}

2. 该异常还经常发生在使用DialogFragment的场景下,DialogFragment也是Fragment的一个子类,其show()方法等同于FragmentTransaction.add()方法,dismiss()方法等同于FragmentTransaction.remove()方法。所以发生异常的原因同上。解决方案如下:

  if (dialogFragment.isAdded())
              dialogFragment.dismiss();
else
              dialogFragment.show();      
解决过程如下:      
然后,我阅读我的代码,然后又跑了APP,再仔细看了错误提示,想到了可能是用户快速点击一个按钮,然后调用了多次,dialogfragment的show方法。这样就会导致fragment被多次添加。这时候只需要在show的时候 增加判断就可以了。      
其实是个很简单的bug,我想分享的是,有时候我们认为不会出现的Bug出现了,那就要考虑到 用户是否是正常使用的。明明一个按钮 点击一次就可以了,却有用户连续点击,就像我们给用户提示toast的时候,一般都会做一个保护,防止用户多次点击,连续弹相同的提示。那么我们的按钮也需要做同样的保护,比如部分功能按钮,我们做一个防止连续点击的保护。如,获取验证码,某些开关按钮等。      
1.分享一个按钮连续点击的功能,我们可以通过Handler来做一个延迟消息。      
private Handler handler = new Handler();
    public void controlViewClickable(final View view, long delay) {
        // 如果已经是不可点击,就不点击
        if(null == view || !view.isClickable())
            return;
        view.setClickable(false);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                view.setClickable(true);
            }
        },delay);
    }
           
2.借着这次看fragment的时候,顺便看了一下FragmentStatePagerAdapter和FragmentPagerAdapter的区别。
相对性能来说,FragmentStatePagerAdapter比较有优势,它有一个setOffscreenPageLimit()的方法,可以设置缓存页面的数量。加载的Fragment的数量超过了设置的值,则会回收掉多余的页面。在我们需要的时候,重新加载一个Fragment。      
而FragmentPagerAdapter,会把所有的Fragment都保存下来。不会自动去回收。当然,重新回到该页面就会很快,不用消耗流量去重新加载了。      
一般使用的时候,页面较少则使用FragmentPagerAdapter。