如何在Android上管理starActivityForResult

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

举个例子,在主活动中,我调用了第二个活动。在这个活动中,我正在检查手机的一些功能,比如它有没有摄像头。如果没有,我会关闭这个活动。同样,在准备MediaRecorderMediaPlayer的过程中,如果出现问题,我会关闭这个活动。

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

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

874173 次浏览

如何查看主活动的结果?

你需要重写#0,然后检查它的参数:

  • requestCode标识哪个应用程序返回这些结果。这是您在调用startActivityForResult()时定义的。
  • resultCode通知您此应用程序是成功、失败还是不同
  • data保存此应用程序返回的任何信息。这可能是null

从您的FirstActivity,使用startActivityForResult()方法调用SecondActivity

例如:

int LAUNCH_SECOND_ACTIVITY = 1Intent 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()方法编写以下代码。

@Overrideprotected 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

要以静态编程语言更好地实现两个活动之间的数据传递,请参阅'一个更好的方式来传递活动之间的数据

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

@Overrideprotected 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;}
@Overrideprotected void onResume() {super.onResume();
if(new_latlng){PhysicalTagProperties.this.setLocation(global_lat, global_lng);new_latlng=false;}}

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

首先,您在第一个Activity中使用startActivityForResult()和参数,如果您想将数据从第二个Activity发送到第一个Activity,然后使用IntentsetResult()方法传递值,并在第一个Activity中的onActivityResult()方法中获取该数据。

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

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

我有一个问题

new Intent();

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

getIntent();

获取当前的意图。

对于那些有问题的人活动返回错误请求

如果您从您的Fragment调用startActivityForResult(),则请求代码将由拥有该片段的活动更改。

如果您想在活动中获得正确的结果代码,请尝试以下操作:

更改:

startActivityForResult(intent, 1);到:

getActivity().startActivityForResult(intent, 1);

示例

要在上下文中查看整个过程,这里有一个补充答案。更多解释请参见我更全面的回答

输入图片描述

MainActivity.java

public class MainActivity extends AppCompatActivity {
// Add a different request code for every activity you are starting from hereprivate static final int SECOND_ACTIVITY_REQUEST_CODE = 0;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
// "Go to Second Activity" button clickpublic void onButtonClick(View view) {
// Start the SecondActivityIntent intent = new Intent(this, SecondActivity.class);startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);}
// This method is called when the second activity finishes@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);
// check that it is the SecondActivity with an OK resultif (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {if (resultCode == RESULT_OK) { // Activity.RESULT_OK
// get String data from IntentString returnString = data.getStringExtra("keyName");
// set text view with stringTextView textView = (TextView) findViewById(R.id.textView);textView.setText(returnString);}}}}

SecondActivity.java

public class SecondActivity extends AppCompatActivity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);}
// "Send text back" button clickpublic void onButtonClick(View view) {
// get the text from the EditTextEditText editText = (EditText) findViewById(R.id.editText);String stringToPassBack = editText.getText().toString();
// put the String to pass back into an Intent and close this activityIntent intent = new Intent();intent.putExtra("keyName", stringToPassBack);setResult(RESULT_OK, intent);finish();}}

这是Android上的一个常见问题

它可以分解成三块

  1. 开始活动B(发生在活动A中)
  2. 设置请求的数据(发生在活动B中)
  3. 接收请求的数据(发生在活动A中)
  1. 开始活动b
Intent i = new Intent(A.this, B.class);startActivity(i);
  1. 设置请求的数据

在本部分中,您将决定是否要在特定事件发生时发回数据。

例如:在活动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响应代码

  1. 检索结果

对于那个覆盖onActivityResult方法

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RES_CODE_A) {
// b1 was clickedString x = data.getStringExtra("RES_CODE_A");
}else if(resultCode == RES_CODE_B){
// b2 was clicked}else{// The back button was clicked}}

你需要重写Activity.onActivityResult():

@Overrideprotected 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{
}}

ActivityResult注册表是推荐的方法

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

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

添加到您的build.gradle

def activity_version = "1.2.0-beta01"
// Java language implementationimplementation "androidx.activity:activity:$activity_version"// Kotlinimplementation "androidx.activity:activity-ktx:$activity_version"

如何使用预构建合同

此新API具有以下预构建功能

  1. TakeVideo
  2. 选择联系人
  3. 获取内容
  4. 获取内容
  5. OpenDocument
  6. OpenDocuments
  7. 文档类型
  8. 文档创建人
  9. 拨号
  10. 拍摄
  11. 请求权限
  12. 请求权限

下面的例子使用了akePicture合约:

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只是一个回调,它返回一个可空位图-它是否为null取决于onActivityResult进程是否成功。prepareCall然后将此调用注册到ComponentActivity上的一个名为ActivityResultRegistry的新功能中-我们稍后会回来。ActivityResultContracts.TakePicture()是Google为我们创建的内置助手之一,最后调用takePicture实际上会以与之前Activity.startActivityForResult(intent, REQUEST_CODE)相同的方式触发Intent。

如何编写自定义合同

一个简单的合约,它将Int作为输入并返回一个字符串,请求的活动在结果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)}}}

检查官方留档以获取更多信息。

在你的主要活动

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);
findViewById(R.id.takeCam).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent=new Intent(getApplicationContext(),TakePhotoActivity.class);intent.putExtra("Mode","Take");startActivity(intent);}});findViewById(R.id.selectGal).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent=new Intent(getApplicationContext(),TakePhotoActivity.class);intent.putExtra("Mode","Gallery");startActivity(intent);}});}
@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);
}

在要显示的第二个活动中

private static final int CAMERA_REQUEST = 1888;private ImageView imageView;private static final int MY_CAMERA_PERMISSION_CODE = 100;private static final int PICK_PHOTO_FOR_AVATAR = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_take_photo);
imageView=findViewById(R.id.imageView);
if(getIntent().getStringExtra("Mode").equals("Gallery")){pickImage();}else {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_CAMERA_PERMISSION_CODE);} else {Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);startActivityForResult(cameraIntent, CAMERA_REQUEST);}}}}public void pickImage() {Intent intent = new Intent(Intent.ACTION_PICK);intent.setType("image/*");startActivityForResult(intent, PICK_PHOTO_FOR_AVATAR);}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == MY_CAMERA_PERMISSION_CODE){if (grantResults[0] == PackageManager.PERMISSION_GRANTED){Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);startActivityForResult(cameraIntent, CAMERA_REQUEST);}else{Toast.makeText(this, "Camera Permission Denied..", Toast.LENGTH_LONG).show();}}}
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) {Bitmap photo = (Bitmap) data.getExtras().get("data");imageView.setImageBitmap(photo);}if (requestCode == PICK_PHOTO_FOR_AVATAR && resultCode == Activity.RESULT_OK) {if (data == null) {Log.d("ABC","No Such Image Selected");return;}try {Uri selectedData=data.getData();Log.d("ABC","Image Pick-Up");imageView.setImageURI(selectedData);InputStream inputStream = getApplicationContext().getContentResolver().openInputStream(selectedData);Bitmap bitmap = BitmapFactory.decodeStream(inputStream);Bitmap bmp=MediaStore.Images.Media.getBitmap(getContentResolver(),selectedData);} catch (FileNotFoundException e) {e.printStackTrace();} catch(IOException e){
}}}

我将在简短的回答中用androidx发布新的“方式”(因为在某些情况下您不需要自定义注册表或合约)。如果您想了解更多信息,请参阅:从活动中获取结果

重要:实际上Android X的向后兼容性bug,因此您必须在Gradle文件中添加fragment_version否则你会得到一个异常“新结果API错误:只能使用较低的16位请求代码”

dependencies {
def activity_version = "1.2.0-beta01"// Java language implementationimplementation "androidx.activity:activity:$activity_version"// Kotlinimplementation "androidx.activity:activity-ktx:$activity_version"
def fragment_version = "1.3.0-beta02"// Java language implementationimplementation "androidx.fragment:fragment:$fragment_version"// Kotlinimplementation "androidx.fragment:fragment-ktx:$fragment_version"// Testing Fragments in IsolationdebugImplementation "androidx.fragment:fragment-testing:$fragment_version"}

现在您只需添加活动的这个成员变量。这使用预定义的注册表和通用契约。

public class MyActivity extends AppCompatActivity{
...
/*** Activity callback API.*/// https://developer.android.com/training/basics/intents/resultprivate ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Overridepublic void onActivityResult(ActivityResult result) {switch (result.getResultCode()) {case Activity.RESULT_OK:Intent intent = result.getData();// Handle the IntentToast.makeText(MyActivity.this, "Activity returned ok", Toast.LENGTH_SHORT).show();break;case Activity.RESULT_CANCELED:Toast.makeText(MyActivity.this, "Activity canceled", Toast.LENGTH_SHORT).show();break;}}});

在新的API之前,您有:

btn.setOnClickListener(new View.OnClickListener() {
@Overridepublic void onClick(View v) {Intent intent = new Intent(MyActivity .this, EditActivity.class);startActivityForResult(intent, Constants.INTENT_EDIT_REQUEST_CODE);}});

您可能会注意到请求代码现在由Google框架生成(并保留)。你的代码变成:

 btn.setOnClickListener(new View.OnClickListener() {
@Overridepublic void onClick(View v) {Intent intent = new Intent(MyActivity .this, EditActivity.class);mStartForResult.launch(intent);}});

start ActivityForResult:在Android X中已弃用

对于新的的方式,我们有registerForActivityResult

Java:

 // You need to create a launcher variable inside onAttach or onCreate or global, i.e, before the activity is displayedActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),new ActivityResultCallback<ActivityResult>() {@Overridepublic void onActivityResult(ActivityResult result) {if (result.getResultCode() == Activity.RESULT_OK) {Intent data = result.getData();// your operation....}}});
public void openYourActivity() {Intent intent = new Intent(this, SomeActivity.class);launchSomeActivity.launch(intent);}

静态编程语言:

var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->if (result.resultCode == Activity.RESULT_OK) {val data: Intent? = result.data// your operation...}}
fun openYourActivity() {val intent = Intent(this, SomeActivity::class.java)resultLauncher.launch(intent)}

优势:

  1. 新的方法是降低当我们从一个片段或另一个活动调用活动时所面临的复杂性
  2. 轻松请求任何许可并获得回调

静态编程语言

假设A和B是活动,导航从A->B开始我们需要从A<-B

返回结果

一个

    // calling the Activity BresultLauncher.launch(Intent(requireContext(), B::class.java))
// we get data in here from Bprivate var resultLauncher =registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->when (result.resultCode) {Activity.RESULT_OK -> {result.data?.getStringExtra("VALUE")?.let {// data received here}}Activity.RESULT_CANCELED -> {// cancel or failure}}}

B

    // Sending result value back to Aif (success) {setResult(RESULT_OK, Intent().putExtra("VALUE", value))} else {setResult(RESULT_CANCELED)}