首页 文章

java.lang.IllegalStateException:使用DialogFragment在onSaveInstanceState之后无法执行此操作

提问于
浏览
33

我面临着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");
    }
}

10 回答

  • 4

    Activity 中,在显示 dialog 之前,你可以做这样的事情

    getSupportFragmentManager().executePendingTransactions();
    

    这对我有用 .

  • 45

    以下是另一个帖子中的答案:

    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();
    
  • 0

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

    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();
    
  • 4

    可能是,响应HandleMessage的处理程序与被破坏的活动相关联 .

    即:如果你旋转屏幕,旧的被破坏的活动将处理消息,然后你将调用showDialog,并抛出异常:

    在旧的被破坏的活动调用了他的onSaveInstanceState之后,您正在创建一个对话框 .

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


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

  • 2
    fragmentView.post(() -> {
                FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
                YourDialog yourDialog = YourDialog.newInstance();
                yourDialog.show(ft, "text_data");
            });
    

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

  • 8

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

    我用这种方式解决了这个问题:

    • 在onSaveInstanceState中我取消延迟的任务

    • 在onRestoreInstanceState中,如果在销毁活动时出现延迟任务,则重新创建任务

  • 1

    答太晚,但可能是正确的答案 . 我创建了一个父类,并从中扩展了对话框片段

    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");
        }
    }
    

    }

  • 0

    onPostResume() 使用post resume方法来完成你的工作..我认为你在onRestart或onResume中调用show dialog方法,所以避免它并使用 onPostResume() 来显示你的对话框 .

  • 0

    您可以检查当前活动是否为isActive(),并且仅在这种情况下启动DialogFragment的片段事务 . 我有一个类似的问题,这个检查解决了我的情况 .

  • -1

    有用:

    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()&&!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();
                    }
                }
    

相关问题