在我的活动中,我通过 startActivityForResult
从主要活动中调用第二个活动。在我的第二个活动中,有一些方法可以完成此活动(可能没有结果),但是,其中只有一个返回结果。
例如,从主要活动中,我调用了第二个活动。在这个活动中,我正在检查手机的一些功能,例如它是否有摄像头。如果没有,那么我将关闭此活动。另外,在准备 MediaRecorder
或 MediaPlayer
期间,如果出现问题,我将关闭此活动。
如果它的设备有摄像头并且录制完全完成,那么在录制视频后,如果用户点击完成按钮,我会将结果(录制视频的地址)发送回主活动。
如何检查主要活动的结果?
在您的 FirstActivity
中,使用 startActivityForResult()
方法调用 SecondActivity
。
例如:
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
要在 Kotlin 中以更好的方式在两个 Activity 之间传递数据,请通过 'A better way to pass data between Activities'。
如何检查主要活动的结果?
您需要覆盖 Activity.onActivityResult()
,然后检查其参数:
requestCode 标识哪个应用程序返回了这些结果。这是您在调用 startActivityForResult() 时定义的。
resultCode 通知您此应用程序是成功、失败还是其他情况
data 包含此应用程序返回的任何信息。这可能为空。
例子
要在上下文中查看整个过程,这是一个补充答案。有关详细说明,请参阅 my fuller answer。
https://i.stack.imgur.com/Tyhf8.png
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();
}
}
作为 the answer from Nishant 的补充,返回活动结果的最佳方式是:
Intent returnIntent = getIntent();
returnIntent.putExtra("result",result);
setResult(RESULT_OK,returnIntent);
finish();
我遇到了问题
new Intent();
然后我发现正确的方法是使用
getIntent();
获取当前意图。
Intent
感觉有点奇怪,它的存在只是为了保存一个 Bundle
并且没有像操作或组件这样的正常值。但是修改用于启动当前活动的 Intent
也感觉有点奇怪(并且有潜在危险?)。所以我搜索了 Android 本身的源代码,发现他们总是创建一个新的 Intent
来用作结果。例如,github.com/aosp-mirror/platform_frameworks_base/blob/…
getIntent()
似乎是将数据返回到未知活动的完美方式,从那里调用活动。谢谢!
startActivityForResult:在 Android X 中已弃用
对于 new 方式,我们有 registerForActivityResult
。
在 Java 中:
// You need to create a launcher variable inside onAttach or onCreate or global, i.e, before the activity is displayed
ActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public 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)
}
优势:
新方法是降低我们从片段或另一个活动调用活动时面临的复杂性轻松请求任何许可并获得回调
Activity.RESULT_OK
) 时,result.resultCode
仍然为 0。
对于那些对wrong requestCode in onActivityResult有问题的人
如果您从 Fragment
调用 startActivityForResult()
,则 requestCode 将由拥有 Fragment 的 Activity 更改。
如果您想在活动中获得正确的 resultCode,请尝试以下操作:
改变:
startActivityForResult(intent, 1);
致:
getActivity().startActivityForResult(intent, 1);
ActivityResultRegistry 是推荐的方法
ComponentActivity
现在提供了一个 ActivityResultRegistry
,可让您处理 startActivityForResult()
+onActivityResult()
和 requestPermissions()
+onRequestPermissionsResult()
流,而无需覆盖 Activity
或 Fragment
中的方法,通过以下方式提高类型安全性ActivityResultContract
,并提供用于测试这些流的挂钩。
强烈建议使用 Android 10 Activity 1.2.0-alpha02 和 Fragment 1.3.0-alpha02 中引入的 Activity Result API。
将此添加到您的 build.gradle
def activity_version = "1.2.0-beta01"
// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"
如何使用预建合约
这个新的 API 具有以下预建功能
TakeVideo PickContact GetContent GetContents OpenDocument OpenDocuments OpenDocumentTree CreateDocument Dial TakePicture RequestPermission RequestPermissions
一个使用 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 作为输入并返回一个字符串,请求的 Activity 在结果 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)
}
}
}
查看 this official documentation 了解更多信息。
prepareCall
如果要使用活动结果更新用户界面,则不能使用 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;
}
}
这看起来很傻,但效果很好。
我将在简短的回答中发布带有 Android X 的新“方式”(因为在某些情况下您不需要自定义注册表或合同)。如果您想了解更多信息,请参阅:Getting a result from an activity
重要提示:Android X 的向后兼容性实际上存在一个错误,因此您必须在 Gradle 文件中添加 fragment_version
。 否则会出现异常“New result API error : Can only use lower 16 bits for requestCode”。
dependencies {
def activity_version = "1.2.0-beta01"
// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"
def fragment_version = "1.3.0-beta02"
// Java language implementation
implementation "androidx.fragment:fragment:$fragment_version"
// Kotlin
implementation "androidx.fragment:fragment-ktx:$fragment_version"
// Testing Fragments in Isolation
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}
现在你只需要添加你的活动的这个成员变量。这使用预定义的注册表和通用合同。
public class MyActivity extends AppCompatActivity{
...
/**
* Activity callback API.
*/
// https://developer.android.com/training/basics/intents/result
private ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
switch (result.getResultCode()) {
case Activity.RESULT_OK:
Intent intent = result.getData();
// Handle the Intent
Toast.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() {
@Override
public 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() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MyActivity .this, EditActivity.class);
mStartForResult.launch(intent);
}
});
首先,您将 startActivityForResult()
与第一个 Activity
中的参数一起使用,如果您想将数据从第二个 Activity
发送到第一个 Activity
,则使用 Intent
和 setResult()
方法传递值并获取该数据在第一个 Activity
的 onActivityResult()
方法内。
这是Android上非常常见的问题
它可以分为三部分
启动活动 B(在活动 A 中发生) 设置请求的数据(在活动 B 中发生) 接收请求的数据(在活动 A 中发生)
开始活动 B
Intent i = new Intent(A.this, B.class);
startActivity(i);
设置请求的数据
在这一部分中,您决定在特定事件发生时是否要发回数据。
例如:在活动 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 响应代码设置结果
检索结果
对于那个覆盖 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{
// The back button was clicked
}
}
在科特林
假设 A 和 B 是导航来自 A -> B 的活动 我们需要从 A <- B 返回的结果
在一个
// calling the Activity B
resultLauncher.launch(Intent(requireContext(), B::class.java))
// we get data in here from B
private 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
}
}
}
在乙
// Sending result value back to A
if (success) {
setResult(RESULT_OK, Intent().putExtra("VALUE", value))
} else {
setResult(RESULT_CANCELED)
}
在您的主要活动中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.takeCam).setOnClickListener(new View.OnClickListener() {
@Override
public 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() {
@Override
public void onClick(View view) {
Intent intent=new Intent(getApplicationContext(),TakePhotoActivity.class);
intent.putExtra("Mode","Gallery");
startActivity(intent);
}
});
}
@Override
public 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;
@Override
protected 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);
}
@Override
public 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();
}
}
}
@Override
protected 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){
}
}
}
您需要覆盖 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{
}
}
不定期副业成功案例分享
SecondActivity
中发生了一些异常,在这种情况下,您还需要将结果返回到FirstActivity
,因此您可以在 catch 块中将结果设置为"RESULT_CANCELLED"
并返回到FirstActivty
并在FirstActivity's' 'onActivityResult()
您可以检查您是否获得了成功或失败的结果。