如何在 Android 上管理 startActivityForResult?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10407159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:35:58  来源:igfitidea点击:

How to manage startActivityForResult on Android?

androidandroid-intentandroid-activitystartactivityforresult

提问by Hesam

In my activity, I'm calling a second activity from the main activity by startActivityForResult. In my second activity, there are some methods that finish this activity (maybe without a result), however, just one of them returns a result.

在我的活动中,我通过startActivityForResult. 在我的第二个活动中,有一些方法可以完成此活动(可能没有结果),但是,只有其中一个返回结果。

For example, from the main activity, I call a second one. In this activity, I'm checking some features of handset such as does it have a camera. If it doesn't have then I'll close this activity. Also, during the preparation of MediaRecorderor MediaPlayerif a problem happens then I'll close this activity.

例如,从主要活动中,我调用了第二个活动。在本次活动中,我将检查手机的一些功能,例如它是否有摄像头。如果没有,那么我将关闭此活动。此外,在准备过程中MediaRecorderMediaPlayer如果出现问题,我将关闭此活动。

If its device has a camera and recording is done completely, then after recording a video if a user clicks on the done button then I'll send the result (address of the recorded video) back to the main activity.

如果它的设备有摄像头并且录制完成,那么在录制视频后,如果用户单击完成按钮,我会将结果(录制视频的地址)发送回主活动。

How do I check the result from the main activity?

如何检查主要活动的结果?

回答by Nishant

From your FirstActivitycall the SecondActivityusing startActivityForResult()method

从您FirstActivity调用SecondActivityusing startActivityForResult()方法

For example:

例如:

int LAUNCH_SECOND_ACTIVITY = 1
Intent i = new Intent(this, SecondActivity.class);
startActivityForResult(i, LAUNCH_SECOND_ACTIVITY);

In your SecondActivityset the data which you want to return back to FirstActivity. If you don't want to return back, don't set any.

在您的SecondActivity集合中,您要返回的数据FirstActivity。如果您不想返回,请不要设置任何内容。

For example: In SecondActivityif you want to send back data:

例如:SecondActivity如果你想发回数据:

Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
setResult(Activity.RESULT_OK,returnIntent);
finish();

If you don't want to return data:

如果您不想返回数据:

Intent returnIntent = new Intent();
setResult(Activity.RESULT_CANCELED, returnIntent);
finish();

Now in your FirstActivityclass write following code for the onActivityResult()method.

现在在您的FirstActivity课程中为该onActivityResult()方法编写以下代码。

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

    if (requestCode == LAUNCH_SECOND_ACTIVITY) {
        if(resultCode == Activity.RESULT_OK){
            String result=data.getStringExtra("result");
        }
        if (resultCode == Activity.RESULT_CANCELED) {
            //Write your code if there's no result
        }
    }
}//onActivityResult

回答by Sam

How to check the result from the main activity?

如何检查主要活动的结果?

You need to override Activity.onActivityResult()then check its parameters:

您需要覆盖Activity.onActivityResult()然后检查其参数:

  • requestCodeidentifies which app returned these results. This is defined by you when you call startActivityForResult().
  • resultCodeinforms you whether this app succeeded, failed, or something different
  • dataholds any information returned by this app. This may be null.
  • requestCode确定哪个应用返回了这些结果。这是由您在调用时定义的startActivityForResult()
  • resultCode通知您此应用程序是否成功、失败或不同
  • data保存此应用程序返回的任何信息。这可能是null

回答by Julian Alberto

Complementing the answer from @Nishant,the best way to return the activity result is:

补充@Nishant的回答,返回活动结果的最佳方式是:

Intent returnIntent = getIntent();
returnIntent.putExtra("result",result);
setResult(RESULT_OK,returnIntent);
finish();

I was having problem with

我有问题

new Intent();

Then I found out that the correct way is using

然后我发现正确的方法是使用

getIntent();

to get the current intent

获取当前意图

回答by Suragch

Example

例子

To see the entire process in context, here is a supplemental answer. See my fuller answerfor more explanation.

要在上下文中查看整个过程,这里是一个补充答案。有关更多解释,请参阅我更完整的答案

enter image description here

在此处输入图片说明

MainActivity.java

主活动.java

public class MainActivity extends AppCompatActivity {

    // Add a different request code for every activity you are starting from here
    private static final int SECOND_ACTIVITY_REQUEST_CODE = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // "Go to Second Activity" button click
    public void onButtonClick(View view) {

        // Start the SecondActivity
        Intent intent = new Intent(this, SecondActivity.class);
        startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);
    }

    // This method is called when the second activity finishes
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // check that it is the SecondActivity with an OK result
        if (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) { // Activity.RESULT_OK

                // get String data from Intent
                String returnString = data.getStringExtra("keyName");

                // set text view with string
                TextView textView = (TextView) findViewById(R.id.textView);
                textView.setText(returnString);
            }
        }
    }
}

SecondActivity.java

第二个Activity.java

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

    // "Send text back" button click
    public void onButtonClick(View view) {

        // get the text from the EditText
        EditText editText = (EditText) findViewById(R.id.editText);
        String stringToPassBack = editText.getText().toString();

        // put the String to pass back into an Intent and close this activity
        Intent intent = new Intent();
        intent.putExtra("keyName", stringToPassBack);
        setResult(RESULT_OK, intent);
        finish();
    }
}

回答by Tomasz Mularczyk

For those who have problem with wrong requestCode in onActivityResult

对于那些在 onActivityResult 中错误 requestCode问题的人

If you are calling startActivityForResult()from your Fragment, the requestCode is changed by the Activity that owns the Fragment.

如果您startActivityForResult()从您的调用Fragment,则 requestCode 由拥有 Fragment 的 Activity 更改。

If you want to get the correct resultCode in your activity try this:

如果你想在你的活动中获得正确的 resultCode 试试这个:

Change:

改变:

startActivityForResult(intent, 1);To:

startActivityForResult(intent, 1);到:

getActivity().startActivityForResult(intent, 1);

getActivity().startActivityForResult(intent, 1);

回答by DaviF

If you want to update the user interface with activity result, you can't to use this.runOnUiThread(new Runnable() {}Doing this the UI won't refresh with new value. Instead, you can do this:

如果你想用活动结果更新用户界面,你不能使用this.runOnUiThread(new Runnable() {}这样做 UI 不会用新值刷新。相反,您可以这样做:

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

    if (resultCode == RESULT_CANCELED) {
        return;
    }

    global_lat = data.getDoubleExtra("LATITUDE", 0);
    global_lng = data.getDoubleExtra("LONGITUDE", 0);
    new_latlng = true;
}

@Override
protected void onResume() {
    super.onResume();

    if(new_latlng)
    {
        PhysicalTagProperties.this.setLocation(global_lat, global_lng);
        new_latlng=false;
    }
}

This seems silly but works pretty well.

这看起来很傻,但效果很好。

回答by Dharmendra Pratap

First you use startActivityForResult()with parameters in first Activityand if you want to send data from second Activityto first Activitythen pass value using Intentwith setResult()method and get that data inside onActivityResult()method in first Activity.

首先,您首先使用startActivityForResult()with 参数,Activity如果您想将数据从第二个发送Activity到第一个,Activity则使用IntentwithsetResult()方法传递值并onActivityResult()在 first 方法中获取该数据Activity

回答by Rohit Singh

Very common problem in android
It can be broken down into 3 Pieces
1 ) start Activity B (Happens in Activity A)
2 ) Set requested data (Happens in activity B)
3 ) Receive requested data (Happens in activity A)

android中很常见的问题
可以分解为3个部分
1)启动Activity B(发生在Activity A中)
2)设置请求的数据(发生在Activity B中)
3)接收请求的数据(发生在Activity A中)

1) startActivity B

1)开始活动B

Intent i = new Intent(A.this, B.class);
startActivity(i);

2) Set requested data

2) 设置请求数据

In this part, you decide whether you want to send data back or not when a particular event occurs.
Eg: In activity B there is an EditText and two buttons b1, b2.
Clicking on Button b1 sends data back to activity A
Clicking on Button b2 does not send any data.

在这部分中,您决定在发生特定事件时是否要发回数据。
例如:在活动 B 中有一个 EditText 和两个按钮 b1、b2。
单击按钮 b1 将数据发送回活动 A
单击按钮 b2 不会发送任何数据。

Sending data

发送数据

b1......clickListener
{
   Intent resultIntent = new Intent();
   resultIntent.putExtra("Your_key","Your_value");
   setResult(RES_CODE_A,resultIntent);
   finish();
}

Not sending data

不发送数据

b2......clickListener
    {
       setResult(RES_CODE_B,new Intent());
       finish();
    }

user clicks back button
By default, the result is set with Activity.RESULT_CANCEL response code

用户单击后退按钮
默认情况下,结果设置为 Activity.RESULT_CANCEL 响应代码

3) Retrieve result

3) 检索结果

For that override onActivityResult method

对于覆盖 onActivityResult 方法

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

if (resultCode == RES_CODE_A) {

     // b1 was clicked 
   String x = data.getStringExtra("RES_CODE_A");

}
else if(resultCode == RES_CODE_B){

   // b2 was clicked

}
else{
   // back button clicked 
}
}

回答by Nitesh Dev Kunwar

You need to override Activity.onActivityResult()

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

if (resultCode == RESULT_CODE_ONE) {


   String a = data.getStringExtra("RESULT_CODE_ONE");

}
else if(resultCode == RESULT_CODE_TWO){

   // b was clicked

}
else{

}
}

回答by Darish

The ActivityResultRegistry is the recommended approach

ActivityResultRegistry 是推荐的方法

ComponentActivitynow provides an ActivityResultRegistrythat lets you handle the startActivityForResult()+onActivityResult()as well as requestPermissions()+onRequestPermissionsResult()flows without overriding methods in your Activityor Fragment, brings increased type safety via ActivityResultContract, and provides hooks for testing these flows.

ComponentActivity现在提供了一个ActivityResultRegistry,让您无需覆盖or 中的方法即可处理startActivityForResult()+onActivityResult()requestPermissions()+onRequestPermissionsResult()流,通过 提高类型安全性,并提供用于测试这些流的钩子。 ActivityFragmentActivityResultContract

It is strongly recommended to use the Activity Result APIs introduced in AndroidX Activity 1.2.0-alpha02 and Fragment 1.3.0-alpha02.

强烈建议使用 AndroidX Activity 1.2.0-alpha02 和 Fragment 1.3.0-alpha02 中引入的 Activity Result API。

Add this to your build.gradle

将此添加到您的 build.gradle

def activity_version = "1.2.0-alpha03"

// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"

How to use the pre-built contract?

如何使用预建合约?

This new API has the following pre built functionalities

这个新的 API 具有以下预先构建的功能

  1. TakeVideo
  2. PickContact
  3. GetContent
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. Dial
  10. TakePicture
  11. RequestPermission
  12. RequestPermissions
  1. 拍视频
  2. PickContact
  3. 获取内容
  4. 获取内容
  5. 开放文档
  6. 开放文档
  7. 打开文档树
  8. 创建文档
  9. 拨号
  10. 拍照片
  11. 请求权限
  12. 请求权限

An example that uses takePicture contract:

使用 takePicture 合约的示例:

private val takePicture = prepareCall(ActivityResultContracts.TakePicture()) 
     { bitmap: Bitmap? ->
        // Do something with the Bitmap, if present
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button.setOnClickListener { takePicture() }
       }

So what's going on here? Let's break it down slightly. takePictureis just a callback which returns a nullable Bitmap - whether or not it's null depends on whether or not the onActivityResultprocess was successful. prepareCallthen registers this call into a new feature on ComponentActivitycalled the ActivityResultRegistry- we'll come back to this later. ActivityResultContracts.TakePicture()is one of the built-in helpers which Google have created for us, and finally invoking takePictureactually triggers the Intent in the same way that you would previously with Activity.startActivityForResult(intent, REQUEST_CODE).

那么这里发生了什么?让我们稍微分解一下。takePicture只是一个回调,它返回一个可为空的位图 - 它是否为空取决于该onActivityResult过程是否成功。prepareCall然后将此调用注册到ComponentActivity名为 the的新功能中ActivityResultRegistry- 我们稍后会回到这个问题。ActivityResultContracts.TakePicture()是 Google 为我们创建的内置帮助程序之一,最终调用takePicture实际上会以与之前使用Activity.startActivityForResult(intent, REQUEST_CODE).

How to write a custom contract?

如何编写自定义合同?

Simple contract that takes an Int as an Input and returns a String that requested Activity returns in the result Intent.

将 Int 作为输入并返回请求 Activity 在结果 Intent 中返回的 String 的简单合约。

    class MyContract : ActivityResultContract<Int, String>() {

    companion object {
        const val ACTION = "com.myapp.action.MY_ACTION"
        const val INPUT_INT = "input_int"
        const val OUTPUT_STRING = "output_string"
    }

    override fun createIntent(input: Int): Intent {
        return Intent(ACTION)
            .apply { putExtra(INPUT_INT, input) }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): String? {
        return when (resultCode) {
            Activity.RESULT_OK -> intent?.getStringExtra(OUTPUT_STRING)
            else -> null
        }
    }
}



    class MyActivity : AppCompatActivity() {

    private val myActionCall = prepareCall(MyContract()) { result ->
        Log.i("MyActivity", "Obtained result: $result")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        button.setOnClickListener {
            myActionCall(500)
        }
    }
}

Check thisofficial documentation for more info.

查看官方文档以获取更多信息。