DialogFragment在Activity执行onSaveInstanceState完成后调用show报BUG的解决方案

在开发过程中,发现了这样一个BUG:在用DialogFragment的show(FragmentTransaction transaction,String tag)方法时会报如下BUG:(中间空白为项目代码请忽律)

 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
     at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1493)
     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1511)
     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:638)
     at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:617)
     at android.support.v4.app.DialogFragment.show(DialogFragment.java:156)


     
     at com.android.webview.chromium.WebViewContentsClientAdapter.handleJsAlert(W
     at org.chromium.android_webview.AwContentsClientBridge.handleJsAlert(A
     at org.chromium.ui.base.WindowAndroid.nativeOnVSync(Native Method)
     at org.chromium.ui.base.WindowAndroid.access$500(WindowAndroid.java:42)
     at org.chromium.ui.base.WindowAndroid$1.onVSync(WindowAndroid.java:121)
     at org.chromium.ui.VSyncMonitor.onVSyncCallback(VSyncMonitor.java:129)
     at org.chromium.ui.VSyncMonitor.access$400(VSyncMonitor.java:18)
     at org.chromium.ui.VSyncMonitor$1.doFrame(VSyncMonitor.java:84)
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
     at android.view.Choreographer.doCallbacks(Choreographer.java:672)
     at android.view.Choreographer.doFrame(Choreographer.java:605)
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:846)
     at android.os.Handler.handleCallback(Handler.java:739)
     at android.os.Handler.dispatchMessage(Handler.java:95)
     at android.os.Looper.loop(Looper.java:148)
     at android.app.ActivityThread.main(ActivityThread.java:5438)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)

从异常可以看出,该问题为宿主Activity在调用了onSaveInstanceState以后,再向其添加DialogFragment的时候就会报此错误。我们知道commitAllowingStateLoss()方法可以解决Activity在调用了onSaveInstanceState以后,报BUG的问题。但是问题来了,DialogFragment的show(FragmentTransaction transaction,String tag)方法源码如下:

    public int show(FragmentTransaction transaction, String tag) {
        mDismissed = false;
        mShownByMe = true;
        transaction.add(this, tag);
        mViewDestroyed = false;
        mBackStackId = transaction.commit();
        return mBackStackId;
    }

可以看到该方法调用的是commit()(其实这里我们也找到了问题的源头,就在于此)。那么有没有调用commitAllowingStateLoss()的方法呢?答案是我寻找了源码N次,发现没有。怎么办呢?请看如下方法:

            ft.add(f,tmp);
            ft.commitAllowingStateLoss();

ft为:FragmentTransaction。

这里再提供一个自己的想法,用重写show(FragmentTransaction transaction,String tag)方法,再利用反射修改内部参数,修改此方法,代码如下:

     @Override
    public int show(FragmentTransaction transaction, String tag) {
        try {
            Class clazz = Class.forName("android.support.v4.app.DialogFragment");
            Field mDismissed = clazz.getDeclaredField("mDismissed");
            mDismissed.setAccessible(true);
            mDismissed.setBoolean(this,false);
            Field mShownByMe = clazz.getDeclaredField("mShownByMe");
            mShownByMe.setAccessible(true);
            mShownByMe.setBoolean(this,true);
            Field mViewDestroyed = clazz.getDeclaredField("mViewDestroyed");
            mViewDestroyed.setAccessible(true);
            mViewDestroyed.setBoolean(this,false);
            transaction.add(this, tag);
            return transaction.commitAllowingStateLoss();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return -1;
    }

以上2各方法都是经过测试的可用方法。

如有不妥之处请各位大大留言,以待优化,谢谢



你可能感兴趣的:(Android)