【问题标题】:"Failure Delivering Result " - onActivityForResult“传递结果失败” - onActivityForResult
【发布时间】:2013-04-22 08:34:06
【问题描述】:

我有一个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()

标签: android android-intent android-activity android-fragmentactivity


【解决方案1】:

首先,您应该阅读我的blog post 以了解更多信息(它讨论了为什么会发生此异常以及您可以采取哪些措施来防止它)。

调用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 的状态恢复后被调用)。

【讨论】:

  • 在 Fragments 中,我在没有 onPostResume 的情况下使用 onResume。我还没有再看到这个问题,但也许你想对此发表评论。 PS。非常感谢您富有洞察力的帖子!
  • 是的,在Fragment#onResume() 中这样做很好。这是因为FragmentActivity#onPostResume() 调用FragmentActivity#onResumeFragments(),后者调用FragmentManager#dispatchResume(),后者调用Fragment#onResume() 为每个活动的片段。因此,Fragment#onResume()FragmentActivity#onPostResume() 之后调用,所以不会有问题(您可以查看每个相应类的[源代码](goo.gl/Lo1Z1T)以自己验证这一点......或者您可以只是只有我:P)。谢谢!很高兴你认为他们很有见地。 :)
  • @Alex,如果 dialogfragment 进行网络调用,并且在 dialogfragment 获得异步响应之前按下 Home 按钮,则在异步响应中调用 this.dismiss() 将导致状态丢失异常。在这种情况下,什么时候应该调用dismiss()以便没有状态丢失?请注意,请求和响应在对话片段中,而不是在活动中。
  • @crazyhorse 在这种情况下,取消异步任务和/或引发标志以确保不会在 AsyncTask#onPostExecute() 内部调用 dismiss() 可能是个好主意(对话框将是在活动进入后台的情况下由FragmentManager 自动关闭,因此您无需在活动结束后自行关闭对话框。
  • 不知道onPostResume()。修复了我的问题(在从挂起的意图中取消系统对话框后,我在 onResume() 中创建了一个对话框片段,这导致我的应用程序崩溃)。
【解决方案2】:

这类似于@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 订阅者。
【解决方案3】:

你可以使用ft.commitAllowingStateLoss()来解决这个问题。

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

【讨论】:

    【解决方案4】:

    您的 logcat 清楚地表明:“在 onSaveInstanceState 之后无法执行此操作” -- 您的 Activity 那时已经死了,无法返回任何结果。

    只是移动:

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

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

    【讨论】:

    • 谢谢。 finish() 是我做的最后一件事。我的意图代码就在它上面。,我把它移到了顶部,同样的错误。我正在添加代码来回答...
    • 关于最后评论的一点。我实际上没有看到吐司。但是当我在崩溃后重新进入应用程序时,我已经登录了。
    【解决方案5】:

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

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

    【讨论】:

      猜你喜欢
      • 2014-01-13
      • 2021-06-18
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 2013-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多