“失败的交付结果”-onActivityForResult


74

我有一个LoginActivity(用户登录)。基本上,它自己Activity的主题类似于对话框(看起来就像对话框一样)。它出现在上方SherlockFragmentActivity。我想要的是:如果成功登录,则应该有两个FragmentTransaction来更新视图。这是代码:

在中LoginActivity,如果成功登录,

setResult(1, new Intent());

SherlockFragmentActivity

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == 1) {
        LoggedStatus = PrefActivity.getUserLoggedInStatus(this);
        FragmentTransaction t = MainFragmentActivity.this.getSupportFragmentManager().beginTransaction();
        SherlockListFragment mFrag = new MasterFragment();
        t.replace(R.id.menu_frame, mFrag);
        t.commit();

        // Set up Main Screen
        FragmentTransaction t2 = MainFragmentActivity.this.getSupportFragmentManager().beginTransaction();
        SherlockListFragment mainFrag = new FeaturedFragment();
        t2.replace(R.id.main_frag, mainFrag);
        t2.commit();
    }
}

使用此LogCat,它在第一次提交时崩溃:

E/AndroidRuntime(32072): Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
E/AndroidRuntime(32072):    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1299)
E/AndroidRuntime(32072):    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1310)
E/AndroidRuntime(32072):    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541)
E/AndroidRuntime(32072):    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525)
E/AndroidRuntime(32072):    at com.kickinglettuce.rate_this.MainFragmentActivity.onActivityResult(MainFragmentActivity.java:243)
E/AndroidRuntime(32072):    at android.app.Activity.dispatchActivityResult(Activity.java:5293)
E/AndroidRuntime(32072):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3315)

您如何调用startActivityForResult()
Rohit

Answers:


293

首先,您应该阅读我的博客文章以获取更多信息(它讨论了发生此异常的原因以及如何防止该异常)。

调用commitAllowingStateLoss()更多的是破解而不是修复。国家损失是严重的,应不惜一切代价避免。在onActivityResult()调用时,活动/片段的状态可能尚未恢复,因此在此期间发生的任何事务都将因此丢失。这是一个非常重要的错误,必须解决!(请注意,该错误仅在您Activity被系统杀死后回来时才会发生……根据设备的内存大小,有时可能很少见……所以这种错误不是测试时非常容易抓到)。

尝试将交易移入onPostResume()(注意,onPostResume()始终在之后调用,onResume()并且onResume()始终在之后调用onActivityResult()):

private boolean mReturningWithResult = false;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    mReturningWithResult = true;
}

@Override
protected void onPostResume() {
    super.onPostResume();
    if (mReturningWithResult) {
        // Commit your transactions here.
    }
    // Reset the boolean flag back to false for next time.
    mReturningWithResult = false;
}

这似乎有点不可思议,但在做这样的事情是必要的,以确保您FragmentTransactions的始终致力于Activity的状态已经恢复到原来的状态(onPostResume()是保证之后调用Activity的状态有所恢复) 。


4
在Fragments中,我在没有onPostResume的情况下使用onResume。我再也没有看到这个问题,但是也许您想对此发表评论。PS。非常感谢您的深刻见解!
Maragues 2013年

27
是的,这样做Fragment#onResume()很好。这是因为FragmentActivity#onPostResume()call调用了FragmentActivity#onResumeFragments(),而调用了FragmentManager#dispatchResume(),它需要Fragment#onResume()每个活动的片段。因此,Fragment#onResume()在之后被调用,FragmentActivity#onPostResume()这样就不会有问题(您可以为每个相应的类查看[源代码](goo.gl/Lo1Z1T)以为自己进行验证...或者您也可以只是我:P )。谢谢!很高兴您认为他们很有见识。:)
Alex Lockwood

2
@crazyhorse在这种情况下,取消异步任务和/或引发一个标志以确保dismiss()未在内部调用是个好主意AsyncTask#onPostExecute()FragmentManager如果活动进入后台,对话框将自动被关闭),因此活动结束后,您无需自己关闭该对话框)。
Alex Lockwood

1
不知道onPostResume()。解决了我的问题(onResume()从挂起的意图取消系统对话框后,我在创建对话框片段,这使我的应用程序崩溃了)。
EpicPandaForce 2015年

1
@AlexLockwood谢谢你的这篇文章。在您的博客中,您说应该在Activity#onPostResume之后提交事务。但是同时,您说它们可以在Activity#onCreate中提交(甚至在onResume之前运行)。我敢肯定我误解了一些,所以你可以解释一下。
nutella_eater

1

这类似于@Alex Lockwood的答案,但是使用了Runnable

private Runnable mOnActivityResultTask;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    mOnActivityResultTask = new Runnable() {
        @Override
        public void run() {
            // Your code here
        }
    }
}

@Override
protected void onPostResume() {
    super.onPostResume();
    if (mOnActivityResultTask != null) {
        mOnActivityResultTask.run();
        mOnActivityResultTask = null;
    }
}

如果您使用lambdas运行Android 3.0及更高版本,请使用以下命令:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    mOnActivityResultTask = () -> {
        // Your code here
    }
}

我宁愿使用runnable,因为那样可以让您在发生逻辑的地方编写逻辑。以我为例,它来自rx订户。
法比奥

-2

您可以ft.commitAllowingStateLoss()用来解决此问题。

原因:您的ft.commit()方法在之后切换onSaveInstanceState


-2

您的logcat明确说:“在onSaveInstanceState之后无法执行此操作” -您Activity此时已死,无法返回任何结果。

只需移动:

Intent in = new Intent();
setResult(1, in);

到你Activity还活着的地方,一切都会好起来的。并且不要忘记给finish()Activity提供结果。


谢谢。 finish()是我要做的最后一件事。我在它上面有一个意图代码。我正在添加代码来回答...
TheLettuceMaster

关于最后评论的另一点。我实际上看不到吐司。但是当我在崩溃后重新进入应用程序时,我已经登录
。– TheLettuceMaster

-2

在我的情况下,由于以下原因,我遇到了相同的问题

public void onBackPressed() {
    super.onBackPressed();
    setIntents();

}


private void setIntents(){
    Intent searchConstaints=new Intent();
    searchConstaints.putExtra("min",20);
    searchConstaints.putExtra("max",80);
    setResult(101,searchConstaints);
    finish();
}

通过在onBackPressed()中重新安排函数调用来解决

public void onBackPressed() {

    setIntents();
    super.onBackPressed();

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.