当按下返回按钮时,setResult无法正常工作。

115

我想在按下返回键后设置setResult。 我在onDestroy中调用此函数。

Intent data = new Intent();
setResult(RESULT_OK, data) 

但是,当涉及到

onActivityResult(int requestCode, int resultCode, Intent data) 

resultCode为0(RESULT_CANCELED),data为“null”。

那么,我如何从通过BACK按钮终止的activity中传递结果?

10个回答

169

您需要重写onBackPressed()方法并在调用超类之前设置结果,即

@Override
public void onBackPressed() {
    Bundle bundle = new Bundle();
    bundle.putString(FIELD_A, mA.getText().toString());
    
    Intent mIntent = new Intent();
    mIntent.putExtras(bundle);
    setResult(RESULT_OK, mIntent);
    super.onBackPressed();
}

23
请注意,如果您使用这种方法,必须在调用setResult()之后再调用super.onBackPressed(),如上所示,否则您将再次遇到原来的问题! - jengelsma
1
这是最佳答案。如果我们重写 onPause() 或 onDestroy(),onBackPressed() 将首先被调用,并将结果设置为 0。请注意! - Marek
你可以在onCreate中设置默认结果,或者在finish()之前的任何地方都可以。 - Helin Wang
6
我采取了类似的方法,但仍然没有起作用。例如,我的请求代码和意图正在工作,但resultCode始终为0。 - Neon Warge
现在是2020年12月,它仍然可以工作!谢谢。 - Dharmishtha

74

Activity结果必须在调用finish()之前设置。点击返回按钮实际上会在你的activity上调用finish(),因此你可以使用以下代码片段:

@Override
public void finish() {
    Intent data = new Intent();
    setResult(RESULT_OK, data); 

    super.finish();
}

如果在onOptionsItemSelected()中调用NavUtils.navigateUpFromSameTask();,会调用finish(),但是你会得到错误的result code。因此,在onOptionsItemSelected()中,你必须调用finish()而不是navigateUpFromSameTask在onActivityResult中requestCode错误

这在 OP 的情况下可以工作,但不是普遍适用的,对吧?除了 finish() 方法之外,还有更多的方法可以通过 onPause() 和 onDestroy() 来终止应用程序生命周期吗?另请参见我在其他答案中的评论。 - pjv
即使没有这种情况,当API更新引入时,您也不会像onPause()或onDestroy()的行为更改时那样轻松地了解它。这些是您应该重写的方法。 - pjv
6
@pjv - 我不理解你的意思,finishonPauseonDestroy 有什么关系?除了 finish 开始终止进程之外,它们完全没有关联。 - JBM
1
这是目前在minSdk 26 / targetSdk 32上可行的唯一解决方案,覆盖onBackPressed似乎不再起作用。 - avalerio

21

如果您想在onBackPressed事件中设置一些自定义的RESULT_CODE,那么您需要先设置result,然后调用super.onBackPressed(),然后您将在调用者活动的onActivityResult方法中收到相同的RESULT_CODE

    @Override
    public void onBackPressed()
    {
         setResult(SOME_INTEGER);
         super.onBackPressed();
    }

11

我重构了我的代码。最初,我准备了一些数据,并在onDestroy中将其设置为activity result(但这并没有起作用)。现在,每当要返回的数据更新时,我都会设置activity数据,并且在onDestroy中没有任何操作。


这对我不起作用,因为我的数据是在“onPause”中更新的。 - Bostone
1
如果在调用setResult()后,您的活动被重新创建,则您的数据将会丢失。 - Jarett Millard

4
你应该像这样重写 onOptionsItemSelected 方法:
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
        final Intent mIntent = new Intent();
        mIntent.putExtra("param", "value");
        setResult(RESULT_OK, mIntent);
        finish();
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

2

请参考onActivityResult(int, int, Intent)文件

解决方案是检查resultCode是否为Activity.RESULT_CENCELED。如果是,那么它意味着BACK被按下或活动崩溃了。希望这对你们有用,对我有效 :).


这是确切的解决方案。你必须设置结果代码。除了你自己在代码中,没有人可以设置结果。所以,如果结果不是OK,那么要么是返回按键,要么是崩溃。 - John

0
我贴出的答案可能对其他人有帮助: 当设置了 `android:launchMode="singleTask"` 的时候, 我也无法得到结果, 文档上说:
     /* <p>Note that this method should only be used with Intent protocols
 * that are defined to return a result.  In other protocols (such as
 * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
 * not get the result when you expect.  For example, if the activity you
 * are launching uses the singleTask launch mode, it will not run in your
 * task and thus you will immediately receive a cancel result.
 */

并且:

     /* <p>As a special case, if you call startActivityForResult() with a requestCode 
 * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
 * activity, then your window will not be displayed until a result is 
 * returned back from the started activity.  This is to avoid visible 
 * flickering when redirecting to another activity. 
 */

0

onDestroy在生命周期中太晚了,应该重写onPause并检查isFinishing()来确定您的活动是否已经结束。


1
不行,这也太晚了。 - alex2k8
我实际上称之为一个 bug:http://code.google.com/p/android/issues/detail?id=1671。在复杂的应用程序中,我认为由于这个 bug,有些行为是无法编程的。 - pjv
这也非常反直觉。我已经犯了同样的错误,已经有两年了。 - pjv
实际上,这更糟。而且我在编码时发现了这个问题。如果我从onPause中调用setResult,则会执行该操作,但是当执行onActivityReturn时,既不设置resultCode也不设置data。为什么? - Bostone
这就是为什么:“onPause方法的实现必须非常快,因为在此方法返回之前,下一个活动将不会恢复”。http://goo.gl/8S2Y - Bostone

0

尝试覆盖onBackPressed(从Android 5级及以上),或覆盖onKeyDown()并捕获KeyEvent.BUTTON_BACK(请参见{{link1:Android Activity Results}}) 这对我很有用。


0

当您返回到初始活动时,不要依赖于在onPause中执行的任何逻辑。根据文档:

此方法(onPause)的实现必须非常快,因为在此方法返回之前,下一个活动将不会恢复

有关详细信息,请参见http://goo.gl/8S2Y

最安全的方法是在每个结果更改操作完成后设置结果(如您在答案中提到的)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接