onActivityResult 中的操作和“错误在 onSaveInstanceState 之后无法执行此操作”

Posted

技术标签:

【中文标题】onActivityResult 中的操作和“错误在 onSaveInstanceState 之后无法执行此操作”【英文标题】:Actions in onActivityResult and "Error Can not perform this action after onSaveInstanceState" 【发布时间】:2012-08-19 18:17:14 【问题描述】:

实现用户可以登录的应用程序我有以下情况:如果用户已登录,则执行操作,否则启动登录活动以获得结果,如果结果是 Activity.RESULT_OK,则执行操作。

我的问题是要执行的操作是显示一个 DialogFragment,但调用

DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
newFragment.show(ft, "dialog")

在onActivityResult回调中抛出异常:

Caused by: java.lang.IllegalStateException:  
Can not perform this action after onSaveInstanceState

那么我该如何解决呢?我正在考虑在那里升旗并在 onResume 中显示对话框,但我认为这个解决方案有点脏

编辑:添加了更多代码(我按照此示例显示 DialogFragment

当用户请求操作时:

... 
if (!user.isLogged())
 startActivityForResult(new Intent(cnt, Login.class), REQUEST_LOGIN_FOR_COMMENT);

在同一个片段中

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_LOGIN_FOR_COMMENT && resultCode == Activity.RESULT_OK) 
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        DialogFragment newFragment = MyDialogFragment.newInstance();
        newFragment.show(ft, "dialog")
    

如果用户登录登录活动调用;

setResult(Activity.RESULT_OK);
finish();

【问题讨论】:

我认为您应该发布整个代码。似乎您正试图在 onpause 后显示对话框 查看androiddesignpatterns.com/2013/08/… 了解为什么会发生这种情况 【参考方案1】:

我想出的最好的办法是不使用 .show() 而是这样做。

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

【讨论】:

虽然它对我有用,但我觉得不安全,因为我们遗漏了 2 个变量:mDismissed = false; mShownByMe = 真;以上变量在原show函数中修改。 mDismissed 和 mShowByMe 似乎是专门用于跟踪对话框是否被外部调用显示/隐藏的变量。换句话说,他们正好补偿了这种事情。 如何“删除”对话框 你有没有试过在activityOnResult的第一行调用super.onActivityResult()? 调用 super.onActivityResult() 为我解决了这个问题,在解决之前尝试一下。【参考方案2】:

这是对我来说很好的解决方法。

private void alert(final String message) 
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() 
        public void run() 
            AlertDialogFragment alertDialogFragment = AlertDialogFragment.newInstance(message);
            alertDialogFragment.show(getFragmentManager(), ALERT_DIALOG_FRAGMENT);
        
    );        

【讨论】:

【参考方案3】:

如果使用 DialogFragment,唯一对我有用的是使用 dissmissAllowingStateLoss() 关闭 Fragment

【讨论】:

【参考方案4】:

我只是检查一个活动是否正在被销毁。

if (!getActivity().isFinishing()) 
    DialogFragment fragment = MyFragment.newInstance();
    fragment.show(getActivity().getSupportFragmentManager(), MyFragment.TAG);

另见https://***.com/a/41813953/2914140。在DialogFragment 写:

override fun show(manager: FragmentManager?, tag: String?) 
    try 
        val ft = manager?.beginTransaction()
        ft?.add(this, tag)
        ft?.commitAllowingStateLoss()
     catch (ignored: IllegalStateException) 
    

【讨论】:

【参考方案5】:

覆盖show(Fragment manager, String tag)函数,允许状态丢失并通过反射从原始函数更改mDismissed = false;mShownByMe = true;

public class DialogParent extends DialogFragment 

    @Override
    public void show(FragmentManager manager, String tag) 
        try 
            Field mDismissed = DialogFragment.class.getDeclaredField("mDismissed");
            Field mShownByMe = DialogFragment.class.getDeclaredField("mShownByMe");
            mDismissed.setAccessible(true);
            mShownByMe.setAccessible(true);
            mDismissed.setBoolean(this, false);
            mShownByMe.setBoolean(this, true);
         catch (NoSuchFieldException e) 
            e.printStackTrace();
         catch (IllegalAccessException e) 
            e.printStackTrace();
        
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commitAllowingStateLoss();
    

【讨论】:

你也可以用 try-catch 包围父 show 方法,在 catch 中添加对话框并使用你的事务调用 commitAllowingStateLoss()。这样你就不需要任何反思了。【参考方案6】:

这确实有效。

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

【讨论】:

【参考方案7】:

只要在FragmentManager 保存其状态后提交FragmentTrasaction,就会引发此异常。简单明了的方法是在显示DialogFragment 之前检查FragmentManager 是否已经保存状态。

if(!getSupportFragmentManager.isStateSaved()) 
    MyDialogFragment dialogFragment = new MyDialogFragment()
    dialogFragment.show(getSupportFragmentManager, TAG);

【讨论】:

【参考方案8】:

您应该在显示对话框之前调用super.onActivityResult()

【讨论】:

以上是关于onActivityResult 中的操作和“错误在 onSaveInstanceState 之后无法执行此操作”的主要内容,如果未能解决你的问题,请参考以下文章

IllegalStateException:在 onSaveInstanceState 和 onActivityResult 之后无法执行此操作

onActivityResult 方法没有被调用

onActivityResult从日历返回时显示错误

将 OnActivityResult 数据从电容器传回混合应用程序

从另一个 Activity 返回的错误 requestCode onActivityResult

startActivityForResult 和 onActivityResult