如何在Android上管理startActivityForResult?


969

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

例如,从主要活动中,我叫第二个活动。在本活动中,我正在检查手机的某些功能,例如它是否具有摄像头。如果没有,我将关闭此活动。此外,在准备过程中MediaRecorderMediaPlayer如果发生问题,那么我将关闭此活动。

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

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


Answers:


2446

从您的FirstActivity电话SecondActivity使用 startActivityForResult()方法

例如:

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

在您的SecondActivity设置中,要返回的数据FirstActivity。如果您不想返回,请不要进行任何设置。

例如:SecondActivity如果要发送回数据:

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

如果您不想返回数据:

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

现在在您的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

1
setResult(RESULT_CANCELED,returnIntent)中的RESUT_CANCELLED时放置意图的目的是什么?
Ismail Sahin 2013年

4
@ismail假设SecondActivity发生某些异常,在这种情况下,您还需要将结果返回到FirstActivity,因此您可以将结果设置为"RESULT_CANCELLED"catch块,然后返回,FirstActivty然后FirstActivity's' 'onActivityResult()检查是否获得成功或失败的结果。
Nishant

10
因此由您决定,如果您不需要知道取消的原因,则可以只使用setResult(RESULT_CANCELED); 没有任何意图
Ismail Sahin

2
@Lei Leyba调用startActivityForResult()后未调用finish()。第一个Actvity将移至暂停状态。
Nishant 2014年

6
对我来说,它不起作用-.-这就是我讨厌Android的原因-这个系统太不可靠了:-/
Martin Pfeffer 2015年

50

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

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

  • requestCode标识哪个应用返回了这些结果。这是您在致电时定义的startActivityForResult()
  • resultCode 通知您此应用是否成功,失败或其他不同
  • data拥有此应用返回的所有信息。这可能是null

这意味着requestCode仅在第一个活动中使用,而从未在第二个活动中使用?如果第二个活动采用不同的方法,它将发生变化,但会基于意向之外,而不是基于requestCode,对吗?编辑:是的,stackoverflow.com
questions/5104269/…

44

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

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

我有问题

new Intent();

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

getIntent();

得到当前的意图


创建Intent只存在以容纳a Bundle且不具有动作或组件之类的常规值的新感觉有点奇怪。但是修改Intent用于启动当前活动的代码也感觉有些奇怪(可能有危险吗?)。因此,我在源代码中搜索了Android本身,发现它们总是创建一个新的Intent以用作结果。例如,github.com/aosp
mirror/

您好spaaarky21,谢谢您的评论。对不起,我不清楚我到底如何解释该解决方案。那是三年前的事,我只记得我的应用程序由于“新意图”而崩溃,这就是我说“我有问题”时的意思。实际上,我只是尝试使用“ getIntent”,因为当时它很有意义,而且可以正常工作!因此,我决定分享我的解决方案。也许不是说“最佳方式”或“正确方式”的最佳选择,但我坚持我的解决方案。这就是解决我的问题以及其他人的问题的原因。谢谢
朱利安·阿尔贝托

1
哇!效果很好。getIntent()似乎是将数据返回到未知活动(从该活动被调用到的地方)的一种完美方法。谢谢!
sam,

43

要在上下文中查看整个过程,这里是一个补充答案。请参阅我的完整答案以获取更多说明。

在此处输入图片说明

MainActivity.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

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

这可以通过两个不同的应用程序A和应用程序b完成吗?stackoverflow.com/questions/52975645/…–
杰里·亚伯拉罕


10

如果要使用活动结果更新用户界面,则不能使用。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;
    }
}

这似乎很愚蠢,但效果很好。


2

首先startActivityForResult(),在first中使用带参数,Activity如果要从第二个Activity到第一个发送数据,Activity然后使用Intentwith setResult()方法传递值,并onActivityResult()在first中获取该数据Activity


1

android中很常见的问题,
它可以分为3部分
1)开始活动B(在活动A中发生)
2)设置请求的数据(在活动B中发生)
3)接收请求的数据(在活动A中发生)

1)startActivity B

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

2)设置请求的数据

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

传送资料

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

不发送数据

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

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

3)检索结果

对于该重写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 
}
}

1

建议使用ActivityResultRegistry

ComponentActivity现在提供了一个ActivityResultRegistry,使您能够处理startActivityForResult()+ onActivityResult()以及requestPermissions()+ onRequestPermissionsResult()流,而无需在Activityor中覆盖方法,Fragment通过带来更高的类型安全性ActivityResultContract,并提供用于测试这些流的钩子。

强烈建议使用AndroidX活动1.2.0-alpha02和片段1.3.0-alpha02中引入的活动结果API。

将此添加到您的 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"

如何使用预建合同?

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

  1. 拍摄视频
  2. 选择联系
  3. 获取内容
  4. 获取内容
  5. 打开文件
  6. OpenDocuments
  7. OpenDocumentTree
  8. 创建文档
  9. 拨号
  10. 拍照片
  11. 请求权限
  12. 请求权限

使用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() }
       }

那么这是怎么回事?让我们将其分解一下。takePicture只是一个返回可为空的位图的回调-是否为空取决于该onActivityResult过程是否成功。prepareCall然后将此调用注册到ComponentActivity名为的新功能中ActivityResultRegistry-我们稍后会再介绍。ActivityResultContracts.TakePicture()是Google为我们创建的内置帮助程序之一,最终调用takePicture实际上会以您以前使用的相同方式触发Intent Activity.startActivityForResult(intent, REQUEST_CODE)

如何编写自定义合同?

以Int作为输入并返回请求活动的String的简单协定将在结果Intent中返回。

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

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


0
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 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.