在developer.android.com上提供了基础培训。
下面是一个示例,演示如何将现有代码转换为新代码:
旧方式:
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
startActivityForResult(intent, 123);
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == 123) {
doSomeOperations();
}
}
新的方式(Java):
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
someActivityResultLauncher.launch(intent);
}
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
doSomeOperations();
}
}
});
新的方法(Kotlin):
fun openSomeActivityForResult() {
val intent = Intent(this, SomeActivity::class.java)
resultLauncher.launch(intent)
}
var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
doSomeOperations()
}
}
编辑。更好的方法是使其更通用,这样我们可以重复使用它。下面的片段在我的一个项目中使用,但请注意,它没有经过充分测试,可能无法涵盖所有情况。
BetterActivityResult.java
import android.content.Intent;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCaller;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class BetterActivityResult<Input, Result> {
/**
* Register activity result using a {@link ActivityResultContract} and an in-place activity result callback like
* the default approach. You can still customise callback using {@link #launch(Object, OnActivityResult)}.
*/
@NonNull
public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract,
@Nullable OnActivityResult<Result> onActivityResult) {
return new BetterActivityResult<>(caller, contract, onActivityResult);
}
/**
* Same as {@link #registerForActivityResult(ActivityResultCaller, ActivityResultContract, OnActivityResult)} except
* the last argument is set to {@code null}.
*/
@NonNull
public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract) {
return registerForActivityResult(caller, contract, null);
}
/**
* Specialised method for launching new activities.
*/
@NonNull
public static BetterActivityResult<Intent, ActivityResult> registerActivityForResult(
@NonNull ActivityResultCaller caller) {
return registerForActivityResult(caller, new ActivityResultContracts.StartActivityForResult());
}
/**
* Callback interface
*/
public interface OnActivityResult<O> {
/**
* Called after receiving a result from the target activity
*/
void onActivityResult(O result);
}
private final ActivityResultLauncher<Input> launcher;
@Nullable
private OnActivityResult<Result> onActivityResult;
private BetterActivityResult(@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract,
@Nullable OnActivityResult<Result> onActivityResult) {
this.onActivityResult = onActivityResult;
this.launcher = caller.registerForActivityResult(contract, this::callOnActivityResult);
}
public void setOnActivityResult(@Nullable OnActivityResult<Result> onActivityResult) {
this.onActivityResult = onActivityResult;
}
/**
* Launch activity, same as {@link ActivityResultLauncher#launch(Object)} except that it allows a callback
* executed after receiving a result from the target activity.
*/
public void launch(Input input, @Nullable OnActivityResult<Result> onActivityResult) {
if (onActivityResult != null) {
this.onActivityResult = onActivityResult;
}
launcher.launch(input);
}
/**
* Same as {@link #launch(Object, OnActivityResult)} with last parameter set to {@code null}.
*/
public void launch(Input input) {
launch(input, this.onActivityResult);
}
private void callOnActivityResult(Result result) {
if (onActivityResult != null) onActivityResult.onActivityResult(result);
}
}
使用上述方法,您仍然需要在启动活动或片段附加之前或期间进行注册。一旦定义,它可以在活动或片段中重复使用。例如,如果您需要在大多数活动中启动新活动,则可以定义一个名为BaseActivity
的基础活动,并像这样注册一个新的BetterActivityResult
:
BaseActivity.java
public class BaseActivity extends AppCompatActivity {
protected final BetterActivityResult<Intent, ActivityResult> activityLauncher = BetterActivityResult.registerActivityForResult(this);
}
之后,您可以像这样从任何子活动启动活动:
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
activityLauncher.launch(intent, result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
doSomeOperations();
}
})
}
由于您可以在Intent
中设置回调函数,因此您可以将其重用于任何活动。
同样,您还可以使用其他两个构造函数来使用其他活动契约。
onActivityResult
是一个独立的回调函数,而不是一个在“launch”时设置的lambda表达式。原因在于它需要在配置更改或进程死亡/重建后存在(这两种情况都可能发生在其他活动打开时——只需旋转设备即可)。您基于lambda的方法永远无法正确处理这些情况。 - ianhanniballakestartActivityForResult2
。如果你认为使用结果码很繁琐,那么等你接触到这个混乱的烂摊子时,你就会更加失望了。 - rmirabelle从现在开始,startActivityForResult()
已经被弃用,请改用新的方法。
Kotlin示例
fun openActivityForResult() {
startForResult.launch(Intent(this, AnotherActivity::class.java))
}
val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// Handle the Intent
//do stuff here
}
}
替换已弃用的方法startActivityForResult(...)
有4个简单步骤。
在重写方法onActivityResult(..)
的位置 -
ActivityResultLauncher<Intent> activityResultLaunch = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == 123) {
// ToDo : Do your stuff...
} else if(result.getResultCode() == 321) {
// ToDo : Do your stuff...
}
}
});
对于多个自定义请求,请将条件追加为:
if (result.getResultCode() == 123) {
..
} else if(result.getResultCode() == 131){
..
} // so on..
导入:
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
使用startActivityForResult(intent, 123)替代
Intent intent = new Intent(this, SampleActivity.class);
activityResultLaunch.launch(intent);
在SampleActivity.java类中,返回源活动时,代码将保持不变,如下所示 -
Intent intent = new Intent();
setResult(123, intent);
finish();
开心编码! :)
在Java 8中,它可以像这样编写:
ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == AppCompatActivity.RESULT_OK) {
Intent data = result.getData();
// ...
}
}
);
Intent intent = new Intent( ... );
startActivityForResult.launch(intent);
Intent
显然只有一个请求码。 - Martin Zeitler在Kotlin中,我改变了我的代码。
startActivityForResult(intent, Constants.MY_CODE_REQUEST)
和
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
Constants.MY_CODE_REQUEST -> {
...
}
到
registerForActivityResult(StartActivityForResult()) { result ->
onActivityResult(Constants.MY_CODE_REQUEST, result)
}.launch(intent)
和
private fun onActivityResult(requestCode: Int, result: ActivityResult) {
if(result.resultCode == Activity.RESULT_OK) {
val intent = result.data
when (requestCode) {
Constants.MY_CODE_REQUEST -> {
...
希望它对你有用。 :D
onActivityResult
已经被弃用。在registerForActivityResult
方法中需要进行更新。 - Filipe Brito对于那些具有多个 "requestCode" 片段的人,如果您不确定如何处理这些 "requestCode" 的多个结果,则需要了解在新方法中 "requestCode" 是无用的。
我想像你以前是这样编写代码的:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_CODE) {
when (requestCode) {
REQUEST_TAKE_PHOTO -> {
// handle photo from camera
}
REQUEST_PICK_IMAGE_FROM_GALLERY -> {
// handle image from gallery
}
}
}
}
ActivityResultContract
中实现每个请求的结果:val takePhotoForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// handle photo from camera
}
}
val pickImageFromGalleryForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// handle image from gallery
}
}
然后你需要像这样启动那些活动/意图:
private fun startTakePhotoActivity() {
takePhotoForResult.launch(Intent(requireActivity(), TakePhotoActivity::class.java))
}
private fun pickImageFromGallery() {
val pickIntent = Intent(Intent.ACTION_PICK)
pickIntent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/*"
)
pickImageFromGalleryForResult.launch(pickIntent)
}
通过这样做,您可以在项目中消除数百个const val REQUEST_
值。
REQUEST_
整数的值需要时间,而且整数可以用于不同的目的,从而搞乱项目。然而,ActivityResultContracts
仅用于指导开发人员到达正确的点,只有一个目的。这就是区别所在。@TheincredibleJan - Egemen HamutçuonActivityResult
, startActivityForResult
, requestPermissions
, 和 onRequestPermissionsResult
在androidx.fragment
的1.3.0-alpha04
版本中被废弃,而不是在android.app.Activity
中。
相反,你可以使用Activity Result APIs
与registerForActivityResult
。
参考: Kotlin - 从图库选择图片
到目前为止,我找到的最简单的替代方法。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.id.activity_main)
var ivPhoto = findViewById<ImageView>(R.id.ivPhoto)
var btnChoosePhoto = findViewById<Button>(R.id.btnChoosePhoto)
val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
ivPhoto.setImageURI(uri) // Handle the returned Uri
}
btnChoose.setOnClickListener {
getContent.launch("image/*")
}
}
在这里我解释新的方法
private val scan =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ result: ActivityResult ->
if (result.resultCode == AppCompatActivity.RESULT_OK && result.data != null) {
var selected_hub = result!!.data!!.getParcelableExtra<ExtendedBluetoothDevice>(Utils.EXTRA_DEVICE)
Log.d(TAG,"RECONNECT PROCESS "+selected_hub!!.name)
reconnect(selected_hub!!)
}
}
从活动或片段调用此函数
private fun callScan() {
val intent = Intent(requireActivity(), ScanningMeshDevices::class.java)
scan.launch(intent)
}
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
bluetoothAdapter.enable()
Toast.makeText(context, "Permission Granted: ", Toast.LENGTH_SHORT).show()
dynamicButton()
}
else{Toast.makeText(context, "You have to enable bluetooth to use this app.", Toast.LENGTH_SHORT).show()}
}.launch(intent)
startActivityForResult
能够保留。这种新的方式使代码过于复杂,降低了可读性。 - spartygw