【问题标题】:java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState with DialogFragmentjava.lang.IllegalStateException:在使用 DialogFragment 的 onSaveInstanceState 之后无法执行此操作
【发布时间】:2012-12-25 02:23:19
【问题描述】:

我面临 DialogFragment / getSupportFragmentManager / Android 版本 4.x 的问题

01-10 19:46:48.228: E/AndroidRuntime(9879): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1314)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1325)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:532)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions.showDialog(TermsAndConditions.java:256)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions.handleMessage(TermsAndConditions.java:62)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions$IncomingHandler.handleMessage(TermsAndConditions.java:53)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.os.Looper.loop(Looper.java:137)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.app.ActivityThread.main(ActivityThread.java:4441)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at java.lang.reflect.Method.invokeNative(Native Method)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at java.lang.reflect.Method.invoke(Method.java:511)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at dalvik.system.NativeStart.main(Native Method)

在下面的代码中,当我按下它时,它会尝试完成当前活动并返回到上一个活动,它会抛出错误。

代码在旧版本(4.x 之前)上运行良好。

谁能指引我正确的方向。

public class TermsAndConditions extends SherlockFragmentActivity implements LoaderManager.LoaderCallbacks<JSONObject>{
    static final String TAG = "TermsAndConditions";
    private static int titleResource;
    private static int messageResource;

    private IncomingHandler handler = null;
    private static final int SHOW_NETWORK_DIALOG = 3;

    static class IncomingHandler extends Handler {
        private final WeakReference<TermsAndConditions> mTarget; 

        IncomingHandler(TermsAndConditions target) {
            mTarget = new WeakReference<TermsAndConditions>(target);
        }

        @Override
        public void handleMessage(Message msg) {
            TermsAndConditions target = mTarget.get();
            if (target != null) {
                target.handleMessage(msg);
            }
        }
    }
    public void handleMessage(Message msg) {
        switch (msg.what)  {
            case SHOW_NETWORK_DIALOG:
                titleResource = R.string.msg_alert_no_network_title;
                messageResource = R.string.msg_alert_no_network_message;
                showDialog();
                break;
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.web_view);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportLoaderManager().initLoader(0, null, this);
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
    private void loadViewData() {
        //Logic to load content.
    }

    @Override
    public Loader<JSONObject> onCreateLoader(int arg0, Bundle arg1) {
        if (handler == null){
            handler = new IncomingHandler(TermsAndConditions.this);
        }
        return new JsonLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<JSONObject> arg0, JSONObject jsonData) {
        if(jsonDataObject==null || jsonDataObject.length()==0) {
            handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
        } else {
            loadViewData();
        }
    }

    @Override
    public void onLoaderReset(Loader<JSONObject> arg0) {
        if(jsonDataObject==null || jsonDataObject.length()==0) {
            handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
        } else {
            loadViewData();
        }
    }

    public static class JsonLoader extends AsyncTaskLoader<JSONObject> {
        public JsonLoader(Context context) {
            super(context);
        }

        @Override 
        protected void onStartLoading() {
            if (jsonDataObject != null) {
                deliverResult(jsonDataObject);
            }
            if (takeContentChanged() || jsonDataObject == null) {
                forceLoad();
            }
        }

        @Override
        public JSONObject loadInBackground() {
            try {
                return response.getJSONObject("result");
            } catch (JSONException e) {
                return null;
            } catch (Throwable e) {
                return null;
            }
        }

        @Override 
        public void deliverResult(JSONObject newJsonData) {
            if (isReset()) {
                if (jsonDataObject != null) {
                    onReleaseResources(jsonDataObject);
                }
            }
            JSONObject oldData = jsonDataObject;
            jsonDataObject = newJsonData;
            if (isStarted()) {
                super.deliverResult(jsonDataObject);
            }
            if (oldData != null) {
                onReleaseResources(oldData);
            }
        }

        @Override 
        protected void onStopLoading() {
            cancelLoad();
        }

        @Override public void onCanceled(JSONObject jsonData) {
            super.onCanceled(jsonData);
            onReleaseResources(jsonData);
        }

        @Override protected void onReset() {
            super.onReset();
            onStopLoading();
            if (jsonDataObject != null) {
                onReleaseResources(jsonDataObject);
                jsonDataObject = null;
            }
        }

        protected void onReleaseResources(JSONObject jsonData) {
            jsonData = null;
        }
    }
    public static class MyAlertDialogFragment extends DialogFragment {
        public static MyAlertDialogFragment newInstance(int title) {
            MyAlertDialogFragment frag = new MyAlertDialogFragment();
            Bundle args = new Bundle();
            args.putInt("title", title);
            frag.setArguments(args);
            return frag;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            int title = getArguments().getInt("title");
            return new AlertDialog.Builder(getActivity())
                    .setTitle(title)
                    .setMessage(messageResource)
                    .setPositiveButton(R.string.alert_dialog_ok,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {

                            }
                        }
                    )
                    .create();
        }
    }
    public void showDialog() {
        DialogFragment newFragment = MyAlertDialogFragment.newInstance(titleResource);
        newFragment.show(getSupportFragmentManager(), "my_dialog");
    }
}

【问题讨论】:

标签: android illegalstateexception android-dialogfragment android-support-library


【解决方案1】:

这是另一个帖子中的答案:

Actions in onActivityResult and "Error Can not perform this action after onSaveInstanceState"

也在这里:

Refreshing my fragment not working like I thought it should

这是一个解决这个问题的例子:

DialogFragment loadingDialog = createDialog();

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                    transaction.add(loadingDialog, "loading");
                    transaction.commitAllowingStateLoss();  

【讨论】:

  • 这并不能解决我的问题 - 使用 .commitAllowingStateLoss() 时没有错误,但根本没有显示对话框。没有其他方法可以解决这个问题吗?
  • 我也有这个确切的问题,但这并不能解决它。事实上,这个解决方案会在 DialogFragment 显示之前立即强制关闭。
  • 您是否尝试过致电getSupportFragmentManager().executePendingTransactions();。我在transaction.commitAllowingStateLoss();之后调用它
【解决方案2】:

我遇到了同样的问题,我将代码更改如下

newFragment.show(transactionFragment, "dialog");

到:

transactionFragment.add(android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();

完成的代码对我来说效果很好,希望对你有所帮助

FragmentTransaction transactionFragment = getActivity().getSupportFragmentManager().beginTransaction();
    DialogPageListFragment newFragment = new DialogPageListFragment();
    transactionFragment.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    newFragment.setArguments(extras);
    transactionFragment.add(android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();

【讨论】:

  • 根本不叫“show”?它不会破坏 DialogFragment 内部代码的工作方式吗?
  • 这样做,getDialog() 在对话框片段内返回 null。 :(
【解决方案3】:

很可能,响应 HandleMessage 的处理程序与已销毁的活动相关联。

即:如果你旋转屏幕,旧的被销毁的activity会处理消息,然后你会调用showDialog,就会抛出异常:

在旧的已销毁活动调用其 onSaveInstanceState 后,您正在创建一个对话框。

尝试用新创建的活动替换回调,以确保您始终在活动活动中创建对话框。


如果您不旋转,请在 onSaveInstance 上放置一个标志,如“保存”,并在 onRestoreInstance 上禁用它。在您的 handleMessage 方法中,如果“正在保存”标志打开,则不显示对话框,只需打开另一个标志,指示必须在 onResume 上创建对话框。然后在 onResume 方法上,检查是否在该过程的中间,你应该创建对话框,如果是,在 onResume 方法上显示它。

【讨论】:

  • 我的活动只有一个方向。
  • 试试第二段,放一个标志来知道你的Activity何时保存它的实例,并在onResume方法中显示对话框(它在onRestoreInstanceState之后运行)
  • 经过所有的试验和错误,唯一对我有用的解决方案覆盖了扩展对话框片段类中的 show 方法。 code@Override public void show(FragmentManager fm, String tag) { try { super.show(fm, tag); } catch (Throwable e) { //Utils.Log(TAG, e.getMessage()); } }
【解决方案4】:
fragmentView.post(() -> {
    FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
    YourDialog yourDialog = YourDialog.newInstance();
    yourDialog.show(ft, "text_data");
});

这种情况下 post() 方法的目标是等待 Activity 或 Fragment 的 onResume() 完成。 如果您想从 Fragment 显示 DialogFragment,它可以工作。当您想在系统对话框关闭后显示您的对话框时。

【讨论】:

  • 我的代码包含在 getView().post() 中,但我仍然在 Crashlytics 中看到崩溃。
【解决方案5】:

在发布延迟 Runnables handler.postDelayed(Runnable runnable, long delay) 时,我遇到了同样的问题。

我已经这样解决了这个问题:

  1. 在 onSaveInstanceState 我取消了延迟的任务
  2. 在 onRestoreInstanceState 中,如果在销毁活动时存在延迟任务,我会重新创建任务

【讨论】:

  • 听起来不错,但是在 handler.postDelay() 中必须延迟多长时间? 100毫秒就够了
  • 能否粘贴一些示例代码,如何重新创建任务?
【解决方案6】:

答案为时已晚,但可能是正确答案。 我创建了一个父类,并从它扩展了对话框片段

 public class BaseDialogFragment extends DialogFragment {

@Override
public void show(FragmentManager manager, String tag) {
    try {
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag).addToBackStack(null);
        ft.commitAllowingStateLoss();
    } catch (IllegalStateException e) {
        Log.d("ABSDIALOGFRAG", "Exception", e);
    }
}

boolean mIsStateAlreadySaved = false;
boolean mPendingShowDialog = false;

@Override
public void onResume() {
    onResumeFragments();
    super.onResume();
}

public void onResumeFragments(){
    mIsStateAlreadySaved = false;
    if(mPendingShowDialog){
        mPendingShowDialog = false;
        showSnoozeDialog();
    }
}

@Override
public void onPause() {
    super.onPause();
    mIsStateAlreadySaved = true;
}

private void showSnoozeDialog() {
    if(mIsStateAlreadySaved){
        mPendingShowDialog = true;
    }else{
        FragmentManager fm = getFragmentManager();
        BaseDialogFragment snoozeDialog = new BaseDialogFragment();
        snoozeDialog.show(fm, "BaseDialogFragment");
    }
}

}

【讨论】:

  • 好答案,继续。
【解决方案7】:

onPostResume() 使用简历后的方法来做你的工作.. 我认为您在 onRestart 或 onResume 中调用了显示对话框方法,因此请避免使用它并使用 onPostResume() 来显示您的对话框。

【讨论】:

    【解决方案8】:

    您可以检查当前活动是否为活动(),只有在这种情况下才启动 DialogFragment 的片段事务。我遇到了类似的问题,这次检查解决了我的问题。

    【讨论】:

      【解决方案9】:

      有效:

      CheckinSuccessDialog dialog = new CheckinSuccessDialog();
      //dialog.show(getSupportFragmentManager(), null);
      FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
      ft.add(dialog, null);
      ft.commitAllowingStateLoss();
      

      但还是很糟糕,因为出现错误“活动已被销毁”

       ava.lang.IllegalStateException: Activity has been destroyed fragmentTransaction.commitAllowingStateLoss();
      

      所以我的解决方案是添加检查if (!isFinishing()&amp;&amp;!isDestroyed())

      CheckinSuccessDialog fragment = CheckinSuccessDialog.newInstance();
      
        if (fragment instanceof DialogFragment) {
                      DialogFragment dialog = (DialogFragment) fragment;
                      if (!dialog.isAdded()) {
                          fragmentTransaction.add(dialog, 
                                CheckinSuccessDialog.class.getName());
                          if (!isFinishing()&&!isDestroyed()) {
                              fragmentTransaction.commitAllowingStateLoss();
                          }
                      }
      

      解雇时:

        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                  Fragment fragment = getSupportFragmentManager().findFragmentByTag(CheckinSuccessDialog.class.getName());
                  if (fragment != null && fragment instanceof DialogFragment) {
                      DialogFragment dialog = (DialogFragment) fragment;
                      dialog.dismiss();
                      if (!isFinishing()&&!isDestroyed()) {
                          fragmentTransaction.commitAllowingStateLoss();
                      }
                  }
      

      【讨论】:

        【解决方案10】:

        Activity中,在显示对话框之前,您可以执行以下操作

        getSupportFragmentManager().executePendingTransactions();
        

        这对我有用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-04-02
          • 2014-03-05
          • 2014-10-18
          • 1970-01-01
          • 1970-01-01
          • 2015-11-26
          • 1970-01-01
          相关资源
          最近更新 更多