startActivityForResult的替代方法:registerForActivityResult
在startActivityForResult的用法一文的最后提到startActivityForResult方法已经废弃,推荐使用AndroidX中的registerForActivityResult方法。
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull ActivityResultContract<I, O> contract,
@NonNull ActivityResultCallback<O> callback) {
return registerForActivityResult(contract, mActivityResultRegistry, callback);
}
将ActivityResultCallback注册到ActivityResultRegistry中:
@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);
}
1、registerForActivityResult
以注册获取启动Activity返回的结果为例,这里借助ActivityResultContracts,提供了丰富的实现,只需要通过其中的StartActivityForResult()方法即可获取ActivityResultContract<Intent, ActivityResult>:
val register:ActivityResultContract<Intent, ActivityResult> = ActivityResultContracts.StartActivityForResult()
然后再重写ActivityResultCallback接口:
val callback = object : ActivityResultCallback<ActivityResult> {
override fun onActivityResult(result: ActivityResult?) {
Log.d("TAG", "resultCode:${result?.resultCode} data:${result?.data}")
}
}
用前面提到的registerForActivityResult()方法将两者注册:
registerForActivityResult(register, callback)
会获得返回的ActivityResultLauncher对象:
val launcher: ActivityResultLauncher<Intent> = registerForActivityResult(register, callback)
通过该ActivityResultLauncher可以启动我们的Activity:
val intent = Intent()
//
launcher.launch(intent)
看到这里它的优势相比也显而易见,将繁杂的注册和结果回调解耦,不用全部集中在Activity的一个onActivityResult()回调方法中。且每种不同的业务启动不同的Activity,都可以有自己独立的launcher和处理回调。
2、各种ActivityResultContract
Android开发中除了获取启动Activity返回的结果,申请权限的回调。还有非常多的场景,可以通过实现ActivityResultContract<I,O>完成不同场景下的启动:
abstract class ActivityResultContract<I, O> {
/**
* Create an intent that can be used for [android.app.Activity.startActivityForResult].
*/
abstract fun createIntent(context: Context, input: I): Intent
/**
* Convert result obtained from [android.app.Activity.onActivityResult] to [O].
*/
abstract fun parseResult(resultCode: Int, intent: Intent?): O
/**
* An optional method you can implement that can be used to potentially provide a result in
* lieu of starting an activity.
*
* @return the result wrapped in a [SynchronousResult] or `null` if the call
* should proceed to start an activity.
*/
open fun getSynchronousResult(context: Context, input: I): SynchronousResult<O>? {
return null
}
/**
* The wrapper for a result provided in [getSynchronousResult]. This allows differentiating
* between a null [T] synchronous result and no synchronous result at all.
*/
class SynchronousResult<T>(val value: T)
}
而且ActivityResultContracts也提供了非常多现成的实现,比如启动文件选择、获取照片选择结果、启动相机拍照获取结果等等。
3、registerForActivityResult原理
前面了解了startActivityForResult的原理,registerForActivityResult其实也一样,它的注册流程如下:
通过返回的ActivityResultLauncher启动Activity流程:
接着startActivityForResult的原理一文,我们知道结果回调。这里AndroidX库中的ComponentActivity重写了onActivityResult()回调方法:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
通过前面注册的mActivityResultRegistry分发处理这次回调结果,如果没有被处理,还是走原来的处理onActivityResult()回调逻辑。
@MainThread
public final boolean dispatchResult(int requestCode, int resultCode, @Nullable Intent data) {
String key = mRcToKey.get(requestCode);
if (key == null) {
return false;
}
doDispatch(key, resultCode, data, mKeyToCallback.get(key));
return true;
}
紧接着调用doDispatch()方法处理分发结果:
private <O> void doDispatch(String key, int resultCode, @Nullable Intent data,
@Nullable CallbackAndContract<O> callbackAndContract) {
if (callbackAndContract != null && callbackAndContract.mCallback != null
&& mLaunchedKeys.contains(key)) {
ActivityResultCallback<O> callback = callbackAndContract.mCallback;
ActivityResultContract<?, O> contract = callbackAndContract.mContract;
callback.onActivityResult(contract.parseResult(resultCode, data));
mLaunchedKeys.remove(key);
} else {
// Remove any parsed pending result
mParsedPendingResults.remove(key);
// And add these pending results in their place
mPendingResults.putParcelable(key, new ActivityResult(resultCode, data));
}
}
最终是在我们注册的ActivityResultCallback回调中处理onActivityResult结果:
/**
* A type-safe callback to be called when an {@link Activity#onActivityResult activity result}
* is available.
*
* @param <O> result type
*/
public interface ActivityResultCallback<O> {
/**
* Called when result is available
*/
void onActivityResult(@SuppressLint("UnknownNullness") O result);
}
上面整体的流程是: