美文网首页
解决 IllegalStateException: Can no

解决 IllegalStateException: Can no

作者: Sunny君907 | 来源:发表于2017-10-31 17:13 被阅读0次

    java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager:1377)    at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager:504)    at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity:178)    at android.app.Activity.onKeyUp(Activity.java:2207)    at android.view.KeyEvent.dispatch(KeyEvent.java:2664)    at android.app.Activity.dispatchKeyEvent(Activity.java:2437)    atcom.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1975)    at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4013)    at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3987)    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3553)    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3603)    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3572)    at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3679)    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3580)    at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3736)    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3553)    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3603)    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3572)    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3580)    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3553)    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3603)    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3572)    at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3712)    at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3877)    at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2027)    at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1721)    at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1712)    at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2004)    at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)    at android.os.MessageQueue.nativePollOnce(Native Method)    at android.os.MessageQueue.next(MessageQueue.java:138)    at android.os.Looper.loop(Looper.java:123)    at android.app.ActivityThread.main(ActivityThread.java:5028)    at java.lang.reflect.Method.invokeNative(Native Method)    at java.lang.reflect.Method.invoke(Method.java:515)    atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:788)    atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:604)    at dalvik.system.NativeStart.main(Native Method)

    概括的讲,onSaveInstanceState 这个方法会在activity

    将要被kill之前被调用以保存每个实例的状态,以保证在将来的某个时刻回来时可以恢复到原来的状态,但和activity 的生命周期方法onStop

    和 onPause 不一样,与两者并没有绝对的先后调用顺序,或者说并非所有场景都会调用onSaveInstanceState

    方法。那么onSaveInstanceState 方法何时会被调用呢,或者这么问,什么时候activity 会被系统kill

    掉呢?有以下几种比较常见的场景

    (1)用户主动按下home 键,系统不能确认activity 是否会被销毁,实际上此刻系统也无法预测将来的场景,比如说内存占用,应用运行情况等,所以系统会调用onSaveInstanceState保存activity状态 ;

    (2)activity位于前台,按下电源键,直接锁屏;

    (3)横竖屏切换;

    (4)activity B启动后位于activity A之前,在某个时刻activity A因为系统回收资源的问题要被kill掉,A通过onSaveInstanceState保存状态。

    (5)重置应用偏好

    我们的activity在某种场景下处于被kill 掉的边缘,系统就调用了onSaveInstanceState 方法,这个方法里面会调用

    FragmentManager saveAllState 方法,将fragment 的状态保存,在状态保存后用户又主动调了

    onBackPressed ,而这个方法的超类super.onBackPressed 方法会判断FragmentManager

    是否保存了状态,如果已经保存就会抛出IllegalStateException 的异常 。

    此外,还有一个比较类似的异常堆栈信息:

    java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

    这一类异常原因是在activity 调用onSaveInstanceState后,调用了fragmenttransaction  的commit方法所致,如果说onBackPressed 的异常是出现在用户按back后,那么在何处调用commit会导致IllegalStateException异常呢?实际上在api 11(Honeycomb)之前,如果onSaveInstanceState 方法被调用,那么肯定是在onPause 生命周期方法前,但api11以后,却只能保证在onStop 生命周期方法前,和onPause 方法并没有明确的先后调用顺序,正是由于此处生命周期的微小变化,导致api11后,如果在onPause 和 onStop 之间调用commit ,将有可能抛出一个IllegalStateException异常告知状态丢失。

    1、关于commit 方法的调用异常处理方法

    (1)在activity生命周期函数内谨慎使用commit 方法 ,一般情况下如果能在onCreate 中调用,基本不会出现问题,但是如果在onResume onStart 等方法中调用就需要格外注意,比如说FragmetActivity 的onResume 方法 ,在某些场景下onResume 方法被调用之前,可能依然保存着之前的状态导致异常 。

    Dispatch onResume()tofragments. Notethatforbetter inter-operationwitholder versionsoftheplatform,atthepointofthis callthefragments attachedtotheactivity arenotresumed. This meansthatinsomecasestheprevious state may still be saved,notallowing fragment transactionsthatmodifythestate.

    (2)尽可能避免在一些和生命周期函数异步的方法中调用commit,如AsyncTask 等。

    (3)实在没法确定调用时机时,可以用commitAllowingStateLoss 代替 commit ,commitAllowingStateLoss  在状态丢失时不会抛出任何异常,但也正因为如此在一些必须确保状态被保存的场合,最好不要使用  commitAllowingStateLoss  方法。

    eg:

    if(!isFinishing()) {

    FragmentManager fm = getSupportFragmentManager();

    FragmentTransaction ft = fm.beginTransaction();

    DummyFragment dummyFragment = DummyFragment.newInstance();

    ft.add(R.id.dummy_fragment_layout, dummyFragment);

    ft.commitAllowingStateLoss();

    }

    2、针对onbackpress 导致的异常,也有几种解决手段

    (1)在api11 以上 不调用super 的onSaveInstanceState 方法

    protected void onSaveInstanceState(Bundle outState) {//No call for super(). Bug on API Level > 11.}

    这样做的后果会导致activity 和 fragment 的所有状态,在activity 被系统杀死掉后无法保存,所以如果有保存状态的需要,这个方法是不适用的。

    (2)重写 onBackPressed  方法,不调用super.onBackPressed  ,直接调用finish。原因很简单,super.onBackPressed  里面会调用FragmentManager popBackStackImmediate()方法,如果直接掉finish 就不会触发异常,但这种情况只建议在没有使用 Fragments api时调用。

    可以加个标志位

    The exception is threw here (In FragmentActivity):

    @Override

    public void onBackPressed() {

    if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {

    super.onBackPressed();

    }

    }

    InFragmentManager.popBackStatckImmediate(),FragmentManager.checkStateLoss()is called firstly. That's the cause ofIllegalStateException. See the implementation below:

    private void checkStateLoss() {

    if (mStateSaved) { // Boom!

    throw new IllegalStateException(

    "Can not perform this action after onSaveInstanceState");

    }

    if (mNoTransactionsBecause != null) {

    throw new IllegalStateException(

    "Can not perform this action inside of " + mNoTransactionsBecause);

    }

    }

    I solve this problem simply by using a flag to mark Activity's current status. Here's my solution:

    public class MainActivity extends AppCompatActivity {

    /**

    * A flag that marks whether current Activity has saved its instance state

    */

    private boolean mHasSaveInstanceState;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    }

    @Override

    protected void onSaveInstanceState(Bundle outState) {

    mHasSaveInstanceState = true;

    super.onSaveInstanceState(outState);

    }

    @Override

    protected void onResume() {

    super.onResume();

    mHasSaveInstanceState = false;

    }

    @Override

           public void onBackPressed() {

                 if (!mHasSaveInstanceState) {

                // avoid FragmentManager.checkStateLoss()'s throwing IllegalStateException

               super.onBackPressed();

              }

         }

    }

    https://stackoverflow.com/questions/7469082/getting-exception-illegalstateexception-can-not-perform-this-action-after-onsa

    http://blog.csdn.net/edisonchang/article/details/49873669


    相关文章

      网友评论

          本文标题:解决 IllegalStateException: Can no

          本文链接:https://www.haomeiwen.com/subject/adwbpxtx.html