本文已同步发表于我的微信公众号,搜索
代码说即可关注,欢迎与我沟通交流。
文章目录
- startActivityForResult()被标记为过时
- registerForActivityResult替代方案
- 使用示例
- ActivityResultContract 场景
- 自定义ActivityResultContract
- 源码浅析
- registerForActivityResult()
- ActivityResultLauncher#launch()
- 总结
- 资料
startActivityForResult()被标记为过时
一般我们声明的Activity都会继承自 AppCompatActivity (需要引入androidx.appcompat:appcompat库),而AppCompatActivity -> FragmentActivity -> ComponentActivity (->表示继承)。
当我们需要跳转到另一个Activity并需要拿到返回结果时,可以使用startActivityForResult()来实现,然而随着相应库的提高,突然有一天,你会发现startActivityForResult()被标记成过时方法了,如下:

点进去看是 ComponentActivity#startActivityForResult() 及onActivityResult() 被标记为过时:
/**
* {@inheritDoc}
*
* @deprecated use
* {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
* passing in a {@link StartActivityForResult} object for the {@link ActivityResultContract}.
*/
@Override
@Deprecated //被标记为过时
public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
int requestCode) {
super.startActivityForResult(intent, requestCode);
}
/**
* {@inheritDoc}
*
* @deprecated use
* {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
* with the appropriate {@link ActivityResultContract} and handling the result in the
* {@link ActivityResultCallback#onActivityResult(Object) callback}.
*/
@CallSuper
@Override
@Deprecated //被标记为过时
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
ComponentActivity是通过androidx.activity:activity引入的,通过查看该库的更新记录发现是在 androidx.activity:activity:1.2.0-alpha04 中将其废弃的,所以在这个版本之后,如果我们想使用startActivityForResult(),都会看到过时提醒并推荐使用registerForActivityResult()替代。

registerForActivityResult替代方案
使用示例
class ResultApiActivity : AppCompatActivity() {
//1、注册回调函数
private var resultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
//处理返回的结果
val code = result.resultCode //返回码 如:Activity.RESULT_OK、Activity.RESULT_CANCELED
val data = result.data
log("resultCode:$code,data:${intent?.getStringExtra(ResultApi2Activity.KEY_TRANSFER)}")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result_api)
mTvResultApi.setOnClickListener {
//2、启动Intent跳转
resultLauncher.launch(Intent(this, ResultApi2Activity::class.java))
}
}
}
//执行结果: resultCode:-1,data:i'm value from ResultApi2Activity
首先1处在 ComponentActivity 或 Fragment 中调用registerForActivityResult()注册一个回调函数来处理其他页面返回的结果,registerForActivityResult() 接受 ActivityResultContract 和 ActivityResultCallback 作为参数:
- ActivityResultContract<I,O>:定义生成结果所需的
输入类型(I)、输出类型(O),可为Activity传值、拍照、请求权限等基本intent操作提供默认协定,还可以创建自定义协定。 - ActivityResultCallback< O>:带有
onActivityResult(O result)方法的interface类,参数类型是ActivityResultContract<I,O>中定义的输出类型O对象。
registerForActivityResult()方法执行后,返回ActivityResultLauncher类型,用来启动另一个activity,但是此时还没有启动,需要调用ActivityResultLauncher#launch()进行启动。
ActivityResultContract 场景
上一节示例中,registerForActivityResult()的第一个参数我们传入的是ActivityResultContracts.StartActivityForResult(),其是ActivityResultContract接口的具体实现类,我们点进ActivityResultContracts看看其他实现类:
| ActivityResultContracts.xxx | launch()入参 | 结果回调 | 说明 |
|---|---|---|---|
| StartActivityForResult | Intent | ActivityResult(resultCode, intent) | 启动另一个Activity并接收其返回结果 |
| RequestPermission | String,如:Manifest.permission.CAMERA | Boolean | 请求一个权限并接收其授权结果 |
| RequestMultiplePermissions | String[],如arrayOf(Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE) | Map<String, Boolean>,如:for ((permission, isGranted) in permissions) {if (isGranted) {// 权限已授权} else {// 权限未授权}} | 请求多个权限并接收其授权结果 |
| CaptureVideo | Uri | ||
| @RequiresApi(19) CreateDocument | String,如:launcher.launch("document.txt") | Uri | 创建一个新的文档并返回其URI |
| GetContent | String,如:launcher.launch("image/*") | Uri | 打开文件选择器并获取所选文件的URI |
| @RequiresApi(18) GetMultipleContents | String | List< Uri> | 打开文件选择器并获取所选多个文件的URI |
| @RequiresApi(19) OpenDocument | String[] | Uri | 打开现有文档并返回其URI |
| @RequiresApi(21) OpenDocumentTree | Uri | Uri | 打开文档树并返回所选目录的URI |
| @RequiresApi(19) OpenMultipleDocuments | String[] | List< Uri> | 打开多个现有文档并返回它们的URI |
| PickContact | Void | Uri | 打开联系人应用程序并返回所选联系人的URI |
| StartIntentSenderForResult | IntentSenderRequest | ActivityResult | 启动一个IntentSender并接收其返回结果 |
| TakePicture | Uri | Boolean | 启动相机应用程序并拍摄照片 |
| TakePicturePreview | Void | Bitmap | 启动相机应用程序并拍摄预览照片 |
自定义ActivityResultContract
通常来说上一节介绍的ActivityResultContract已经够我们平时开发使用了,不过系统还是提供了自定义ActivityResultContract的能力。
自定义ActivityResultContract可以让我们根据自己的需求创建一个新的Activity或Intent操作,并使用registerForActivityResult()方法将其与ActivityResultLauncher对象绑定。以下是一个自定义ActivityResultContract的示例:
/**
* 1、自定义ActivityResultContract
*/
class CustomContract : ActivityResultContract<Void, String>() {
companion object {
const val DEFAULT_VALUE = "default_value"
}
/**
* 创建Intent
* @param context Context
* @param input 当前类的第一个泛型参数
* @return
*/
override fun createIntent(context: Context, input: Void?): Intent {
return Intent(context, ResultApi2Activity::class.java)
}
/**
* 解析结果,类似于Activity#onActivityResult
* @param resultCode 返回码 [Activity.setResult] 的 resultCode
* @param intent [Activity.setResult] 的 intent
* @return
*/
override fun parseResult(resultCode: Int, intent: Intent?): String {
if (resultCode != Activity.RESULT_OK || intent == null) return DEFAULT_VALUE
return intent.getStringExtra(ResultApi2Activity.KEY_TRANSFER) ?: DEFAULT_VALUE
}
}
//2、Activity中使用自定义Contract
private val mLauncher =
registerForActivityResult(CustomContract()) { result -> log("return result:$result") }
//点击事件中触发launch
mTvCustomContract.setOnClickListener { mLauncher.launch(null)}
//3、目标Activity
class ResultApi2Activity : AppCompatActivity() {
companion object{
const val KEY_TRANSFER = "key_transfer"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setResult(RESULT_OK, intent.putExtra(KEY_TRANSFER, "i'm value from ResultApi2Activity"))
}
}
首先自定义ActivityResultContract,重写了其中的createIntent()和parseResult()方法。createIntent()方法用于创建一个新的Intent对象,因为输入参数为Void,所以不需要传数据给目标Activity。parseResult()方法用于解析目标Activity返回的结果,并将其转换为输出类型String。
接着,使用registerForActivityResult()方法将CustomContract与ActivityResultLauncher对象绑定,并在需要启动该Activity时使用该对象的launch()启动它。
源码浅析
上述示例中主要涉及两个方法,分别为registerForActivityResult()及ActivityResultLauncher#launch()方法,下面重点看下这两个方法。
registerForActivityResult()
//ComponentActivity.java
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull ActivityResultContract<I, O> contract,
@NonNull ActivityResultCallback<O> callback) {
return registerForActivityResult(contract, mActivityResultRegistry, callback);
}
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultRegistry registry,
@NonNull final ActivityResultCallback<O> callback) {
return registry.register(
"activity_rq#" + mNextLocalRequestCode.getAndIncrement(), this, contract, callback);
}
可以看到最终调用了ActivityResultRegistry#register()方法:
public final <I, O> ActivityResultLauncher<I> register(
@NonNull final String key,
@NonNull final LifecycleOwner lifecycleOwner,
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultCallback<O> callback) {
Lifecycle lifecycle = lifecycleOwner.getLifecycle();
//1、判断Lifecycle的状态必须小于Lifecycle.State.STARTED,否则直接抛异常
if (lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
throw new IllegalStateException("LifecycleOwner " + lifecycleOwner + " is "
+ "attempting to register while current state is "
+ lifecycle.getCurrentState() + ". LifecycleOwners must call register before "
+ "they are STARTED.");
}
//2、生成唯一的 requestCode
final int requestCode = registerKey(key);
//3、获取或初始化生命周期容器LifecycleContainer
LifecycleContainer lifecycleContainer = mKeyToLifecycleContainers.get(key);
if (lifecycleContainer == null) {
lifecycleContainer = new LifecycleContainer(lifecycle);
}
//4、注册观察者并将其添加到LifecycleContainer中
LifecycleEventObserver observer = new LifecycleEventObserver() {
@Override
public void onStateChanged(
@NonNull LifecycleOwner lifecycleOwner,
@NonNull Lifecycle.Event event) {
if (Lifecycle.Event.ON_START.equals(event)) {
mKeyToCallback.put(key, new CallbackAndContract<>(callback, contract));
if (mParsedPendingResults.containsKey(key)) {
final O parsedPendingResult = (O) mParsedPendingResults.get(key);
mParsedPendingResults.remove(key);
callback.onActivityResult(parsedPendingResult);
}
final ActivityResult pendingResult = mPendingResults.getParcelable(key);
if (pendingResult != null) {
mPendingResults.remove(key);
callback.onActivityResult(contract.parseResult(
pendingResult.getResultCode(),
pendingResult.getData()));
}
} else if (Lifecycle.Event.ON_STOP.equals(event)) {
mKeyToCallback.remove(key);
} else if (Lifecycle.Event.ON_DESTROY.equals(event)) {
unregister(key);
}
}
};
lifecycleContainer.addObserver(observer);
mKeyToLifecycleContainers.put(key, lifecycleContainer);
//5、初始化ActivityResultLauncher对象并返回
return new ActivityResultLauncher<I>() {
@Override
public void launch(I input, @Nullable ActivityOptionsCompat options) {
mLaunchedKeys.add(key);
onLaunch(requestCode, contract, input, options);
}
@Override
public void unregister() {
ActivityResultRegistry.this.unregister(key);
}
@NonNull
@Override
public ActivityResultContract<I, ?> getContract() {
return contract;
}
};
}
- 1处判断当前
Lifecycle的状态必须小于Lifecycle.State.STARTED,否则直接抛异常。也就是说registerForActivityResult()必须在onStart()之前调用。 - 2处注册键值,该方法会调用
registerKey()方法生成一个唯一的requestCode,并将key和requestCode绑定起来。 - 3处从
mKeyToLifecycleContainers集合中获取与key对应的LifecycleContainer对象。如果不存在,则会创建一个新的LifecycleContainer对象,并将其与lifecycle绑定起来。 - 4处创建一个
LifecycleEventObserver对象,并将其添加到3处的LifecycleContainer对象中。该观察者会在LifecycleOwner对象的生命周期发生变化时执行相应的操作,例如在STARTED状态时将CallbackAndContract对象添加到mKeyToCallback集合中,在STOPPED状态时将其从集合中移除,在DESTROYED状态时调用unregister()方法注销ActivityResultLauncher对象等。 - 5处返回一个
ActivityResultLauncher对象,该对象包含了launch()、unregister()和getContract()三个方法。其中,launch()方法用于启动Activity或Intent操作,unregister()方法用于注销ActivityResultLauncher对象,getContract()方法用于获取与之绑定的ActivityResultContract对象。
ActivityResultLauncher#launch()
上一节中registerForActivityResult()返回了ActivityResultLauncher对象,当启动跳转时,只需要调用launch()方法即可:
public void launch(I input) {
launch(input, null);
}
public abstract void launch( I input, ActivityOptionsCompat options);
可以看到最终调用的 launch( I input, ActivityOptionsCompat options) 方法是一个abstract 抽象方法,其具体实现自然是上一节5处初始化ActivityResultLauncher的地方,可以看到其内部又调用了ActivityResultRegistry#onLaunch(requestCode, contract, input, options) 方法,继续找ActivityResultRegistry初始化的地方,可以找到在ComponentActivity中初始化了ActivityResultRegistry:
this.mActivityResultRegistry = new ActivityResultRegistry() {
public <I, O> void onLaunch(final int requestCode, @NonNull ActivityResultContract<I, O> contract, I input, @Nullable ActivityOptionsCompat options) {
ComponentActivity activity = ComponentActivity.this;
final ActivityResultContract.SynchronousResult<O> synchronousResult = contract.getSynchronousResult(activity, input);
//1、同步检查结果,如果不为空,直接返回contract.getSynchronousResult中的数据
if (synchronousResult != null) {
(new Handler(Looper.getMainLooper())).post(new Runnable() {
public void run() {
dispatchResult(requestCode, synchronousResult.getValue());
}
});
} else {
//2、创建Intent对象
Intent intent = contract.createIntent(activity, input);
Bundle optionsBundle = null;
if (intent.getExtras() != null && intent.getExtras().getClassLoader() == null) {
intent.setExtrasClassLoader(activity.getClassLoader());
}
if (intent.hasExtra("androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE")) {
optionsBundle = intent.getBundleExtra("androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE");
intent.removeExtra("androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE");
} else if (options != null) {
optionsBundle = options.toBundle();
}
if ("androidx.activity.result.contract.action.REQUEST_PERMISSIONS".equals(intent.getAction())) {
String[] permissions = intent.getStringArrayExtra("androidx.activity.result.contract.extra.PERMISSIONS");
if (permissions == null) {
permissions = new String[0];
}
ActivityCompat.requestPermissions(activity, permissions, requestCode);
} else if ("androidx.activity.result.contract.action.INTENT_SENDER_REQUEST".equals(intent.getAction())) {
IntentSenderRequest request = (IntentSenderRequest)intent.getParcelableExtra("androidx.activity.result.contract.extra.INTENT_SENDER_REQUEST");
try {
ActivityCompat.startIntentSenderForResult(activity, request.getIntentSender(), requestCode, request.getFillInIntent(), request.getFlagsMask(), request.getFlagsValues(), 0, optionsBundle);
} catch (final IntentSender.SendIntentException var11) {
(new Handler(Looper.getMainLooper())).post(new Runnable() {
public void run() {
dispatchResult(requestCode, 0, (new Intent()).setAction("androidx.activity.result.contract.action.INTENT_SENDER_REQUEST").putExtra("androidx.activity.result.contract.extra.SEND_INTENT_EXCEPTION", var11));
}
});
}
} else {
ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
}
}
}
};
- 1处用
ActivityResultContract的getSynchronousResult()方法获取同步结果。如果存在同步结果,则会将其返回值通过dispatchResult()方法分发出去。 - 如果1处不存在同步结果,那么就会走2处逻辑,调用
ActivityResultContract的createIntent()方法创建一个新的Intent对象,并根据需要设置Activity或Intent操作的选项。 - 检查
Intent对象的Action属性是否为"androidx.activity.result.contract.action.REQUEST_PERMISSIONS"或"androidx.activity.result.contract.action.INTENT_SENDER_REQUEST"。如果是,则会分别调用ActivityCompat.requestPermissions()方法请求权限或ActivityCompat.startIntentSenderForResult()方法启动相应的操作;如果都不是,则默认调用ActivityCompat.startActivityForResult()方法启动Activity或Intent操作。
//ComponentActivity.java
//1、startActivityForResult()返回结果
@Deprecated
@CallSuper
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (!this.mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
//2、权限申请的结果
@Deprecated
@CallSuper
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (!this.mActivityResultRegistry.dispatchResult(requestCode, -1, (new Intent()).putExtra("androidx.activity.result.contract.extra.PERMISSIONS", permissions).putExtra("androidx.activity.result.contract.extra.PERMISSION_GRANT_RESULTS", grantResults)) && VERSION.SDK_INT >= 23) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
//分发ActivityResultLauncher对象的返回结果
@MainThread
public final boolean dispatchResult(int requestCode, int resultCode, @Nullable Intent data) {
String key = mRcToKey.get(requestCode);
if (key == null) {
return false;
}
mLaunchedKeys.remove(key);
doDispatch(key, resultCode, data, mKeyToCallback.get(key));
return true;
}
//3、处理返回结果
private <O> void doDispatch(String key, int resultCode, @Nullable Intent data,
@Nullable CallbackAndContract<O> callbackAndContract) {
if (callbackAndContract != null && callbackAndContract.mCallback != null) {
ActivityResultCallback<O> callback = callbackAndContract.mCallback;
ActivityResultContract<?, O> contract = callbackAndContract.mContract;
callback.onActivityResult(contract.parseResult(resultCode, data));
} else {
// Remove any parsed pending result
mParsedPendingResults.remove(key);
// And add these pending results in their place
mPendingResults.putParcelable(key, new ActivityResult(resultCode, data));
}
}
主要来看3处的doDispatch()方法:
- 检查
callbackAndContract对象是否为空,如果不为空,则会调用ActivityResultCallback对象的onActivityResult()方法处理返回结果。到这里执行结果就会在registerForActivityResult()中的第2个参数中收到结果。 - 如果上述不成立,会将返回结果存储到
mPendingResults集合中,以便稍后使用。
总结
- 个人认为
startActivityForResult()/onActivityResult()、onRequestPermissionsResult()被标记成过时并不是因为有什么性能问题或者bug,而是通过registerForActivityResult()统一进行收口,为什么这么说呢,因为registerForActivityResult()内部最终还是调用了ComponentActivity中的startActivityForResult()、onActivityResult()、onRequestPermissionsResult()方法,只不过是对其进行了统一的封装而已,简化了使用。 - 使用
registerForActivityResult(),可以通过一个lambda表达式来处理返回结果,避免了繁琐的requestCode和onActivityResult的处理逻辑。此外,registerForActivityResult还支持多个请求码和多个返回结果,使得代码更加清晰和易于维护。
资料
【1】android官网:Activity Result API


















