深入解析 registerForActivityResult
简介
registerForActivityResult方法是官方推出的用于在ComponetActivity和Fragment中替代startActivityForResult方法的新api 官方描述:https://developer.android.google.cn/training/basics/intents/result#kotlin
解析
val getContent = registerForActivityResult ( GetContent ( ) ) { uri: Uri? ->
}
override fun onCreate ( savedInstanceState: Bundle? ) {
val selectButton = findViewById< Button> ( R. id. select_button)
selectButton. setOnClickListener {
getContent. launch ( "image/*" )
}
}
这段代码实现了点击按钮跳转到选择图片的文件选择器界面并获取选择结果的功能。接下来就让我们来看看这段代码是怎么在 ComponetActivity 中实现这样的功能的。 在我们看代码之前,需要始终记住一点,那就是不管 registerForActivityResult 方法中的逻辑如何封装,功能的最终实现本质 还是在 ComponentActivity 中构建一个相应的 Intent 对象传入其 startActivityForResult 方法中,然后在其 onActivityResult 回调中获取结果。
ActivityResultContract
首先我们看到在 registerForActivityResult 方法中传入了两个参数,一个是 GetContent() ,一个是Lambda表达式。那么这个GetContent()到底是个啥?话不多说,上代码。
public final class ActivityResultContracts {
private ActivityResultContracts ( ) { }
public static class GetContent extends ActivityResultContract < String , Uri > {
@CallSuper
@NonNull
@Override
public Intent createIntent ( @NonNull Context context, @NonNull String input) {
return new Intent ( Intent . ACTION_GET_CONTENT)
. addCategory ( Intent . CATEGORY_OPENABLE)
. setType ( input) ;
}
@Nullable
@Override
public final SynchronousResult < Uri > getSynchronousResult ( @NonNull Context context,
@NonNull String input) {
return null ;
}
@Nullable
@Override
public final Uri parseResult ( int resultCode, @Nullable Intent intent) {
if ( intent == null || resultCode != Activity . RESULT_OK) return null ;
return intent. getData ( ) ;
}
}
}
可以看到 GetContent 是抽象类 ActivityResultContract< I,O > 的子类,我们来简要介绍下他重写的三个方法
creatIntent 方法 用于创建 startActivityForResult 方法所需的 Intent 对象getSynchronousResult 方法 若返回值不为 null 会直接将他的返回值作为结果而不调用 startActivityForResult 方法parseResult 方法 用于对从 onActivityResult 回调或 getSynchronousResult 方法中得到的此次结果进行处理
ActivityResultContracts 类中是官方为各种不同用途事先提供好的 ActivityResultContract 子类定义,如果要实现某些特殊的功能也可以自己写一个 ActivityResultContract 的子类
ActivityResultCallback< O >
这就是我们传入 registerForActivityResult 方法的第二个参数(Lambda),一个只有一个方法的接口,当最终结果被 parseResult 方法处理后会传入他的 onActivityResult 回调中,还是给段代码看下
public interface ActivityResultCallback < O > {
void onActivityResult ( @SuppressLint ( "UnknownNullness" ) O result) ;
}
ComponentActivity().registerForActivityResult
我们已经了解了传入的参数大致是什么,现在再来看看 ComponentActivity 的 registerForActivityResult 方法中到底做了什么,话不多说,上代码
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) ;
}
public final < I, O> ActivityResultLauncher< I> registerForActivityResult (
@NonNull ActivityResultContract< I, O> contract,
@NonNull ActivityResultCallback< O> callback) {
return registerForActivityResult ( contract, mActivityResultRegistry, callback) ;
}
可以看到实际调用的是 mActivityResultRegistry 的 register 方法 我们首先来看看这个 register 方法的返回值是个啥
ActivityResultLauncher< I >
public abstract class ActivityResultLauncher < I > {
public void launch ( @SuppressLint ( "UnknownNullness" ) I input) {
launch ( input, null ) ;
}
public abstract void launch ( @SuppressLint ( "UnknownNullness" ) I input,
@Nullable ActivityOptionsCompat options) ;
}
这么看可能还不太清晰,我们再把 GetContent 的父类 ActivityResultContract< I, O > 的代码贴上来对比看看
public abstract class ActivityResultContract < I , O > {
public abstract @NonNull Intent createIntent ( @NonNull Context context,
@SuppressLint ( "UnknownNullness" ) I input) ;
}
再结合上面的 registerForActivityResult 方法代码,我们可以发现 launch 方法和 createIntent 方法的 input 参数是同一个类型!现在我们再来回忆下那段官方代码
val getContent = registerForActivityResult ( GetContent ( ) ) { uri: Uri ? ->
}
override fun onCreate ( savedInstanceState: Bundle ? ) {
val selectButton = findViewById< Button > ( R . id. select_button)
selectButton. setOnClickListener {
getContent. launch ( "image/*" )
}
}
结合上面,我们已经可以大致猜测出内部运行逻辑了 首先我们向 registerForActivityResult 传入了我们自定义的 ActivityResultContract< I,O > 子类对象(此处为 GetContent() )和 ActivityResultCallback< O > (后面的Lambda),registerForActivityResult 返回一个 ActivityResultLauncher< I > 对象(getContent) 当我们需要执行选择图像的操作时,调用 getContent 的 lauch 方法并传入 “image/*” 参数 这个参数又以某种方式传递给了之前 GetContent() 的 createIntent 方法中的 input 参数,于是构建出了一个 Intent 对象 因为 GetContent() 的 SynchronousResult 方法返回 null ,所以这个 Intent 对象通过某种方式被用于 startActivityForResult 中 终于,用户结束了选择,选择的结果以Intent的形式被传入 ComponentActivity 的 onActivityResult 回调中,而这个结果又以某种方式被传入了之前 GetContent() 的 parseResult 方法中得到了处理后的结果 现在,我们再来看两段熟悉的代码,结合 registerForActivityResult 代码有没有想到什么
public abstract class ActivityResultContract < I , O > {
@SuppressLint ( "UnknownNullness" )
public abstract O parseResult ( int resultCode, @Nullable Intent intent) ;
}
public interface ActivityResultCallback < O > {
void onActivityResult ( @SuppressLint ( "UnknownNullness" ) O result) ;
}
没错, parseResult 方法的返回类型正是 ActivityResultCallback< O > 接口的 onActivityResult 回调接受参数的类型! 这意味着在我们得到了通过之前 GetContent() 的 parseResult 处理后的结果后(即选择的图片的 Uri 或 null ),他又被某种方式传递给了 Lambda 的 uri 参数 接着我们便可以在 Lambda 中对最终结果进行我们要进行的操作了(例如上传图片) 现在我们可以来小小的总结下各个类的作用:
ActivityResultContract:我们需要使用官方提供或自定义的子类为以上过程提供特定的 Intent 对象(createIntent),处理返回的结果(parseResult)以及决定是否不执行以上流程直接返回一个相应结果(SynchronousResult)。他就像契约一样对整个过程中的重要节点做出了约束。 ActivityResultCallback< O >:我们需要在其中定义获得经处理的结果的后续操作,这相当于以前使用 startActivityForResult 后在 onActivityResult 回调中的后续操作,但是使用他便可以与 ComponentActivity 解耦。 ActivityResultLauncher< I >:由调用 registerForActivityResult 方法获得,调用其 lauch 方法以启动以上整个流程
ActivityResultRegistry
到此为止,我们已经可以在日常开发中使用 registerForActivityResult 方法了,但既然是完全解析,那么我们还要接着往下看 在上面的流程中,某种方式 就像粘合剂一样将整个流程中的各个步骤粘合在了一起,而实现某种方式 的正是 ActivityResultRegistry,废话少说,上代码
public abstract class ActivityResultRegistry {
@MainThread
public abstract < I , O > void onLaunch (
int requestCode,
@NonNull ActivityResultContract < I , O > contract,
@SuppressLint ( "UnknownNullness" ) I input,
@Nullable ActivityOptionsCompat options) ;
@NonNull
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) {
}
@MainThread
final void unregister ( @NonNull String key) {
}
@MainThread
public final boolean dispatchResult ( int requestCode, int resultCode, @Nullable Intent data) {
}
@MainThread
public final < O > boolean dispatchResult ( int requestCode,
@SuppressLint ( "UnknownNullness" ) O result) {
}
private < O > void doDispatch ( String key, int resultCode, @Nullable Intent data,
@Nullable CallbackAndContract < O > callbackAndContract) {
}
}
不愧是粘合剂,重要方法都比别人多,不要紧,我们一条条来看
register 方法
不知各位是否还记得, registerForActivityResult 方法实际上调用的就是 ActivityResultRegistry 的 register 方法,那我们就从这看起,话不多说,上代码
@NonNull
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 ( ) ;
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." ) ;
}
final int requestCode = registerKey ( key) ;
LifecycleContainer lifecycleContainer = mKeyToLifecycleContainers. get ( key) ;
if ( lifecycleContainer == null ) {
lifecycleContainer = new LifecycleContainer ( lifecycle) ;
}
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) ) {
@SuppressWarnings ( "unchecked" )
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) ;
return new ActivityResultLauncher < I > ( ) {
@Override
public void launch ( I input, @Nullable ActivityOptionsCompat options) {
mLaunchedKeys. add ( key) ;
Integer innerCode = mKeyToRc. get ( key) ;
onLaunch ( ( innerCode != null ) ? innerCode : requestCode, contract, input, options) ;
}
@Override
public void unregister ( ) {
ActivityResultRegistry . this . unregister ( key) ;
}
@NonNull
@Override
public ActivityResultContract < I , ? > getContract ( ) {
return contract;
}
} ;
}
代码较长,我们挑重点来理解
可以看到 ActivityResultRegistry 对于对应的 ComponentActivity 的 lifeCycle 进行了判断,这意味着我们只能在 ComponentActivity 处于 onStart 之前调用 registerForActivityResult 方法进行 register 操作,否则会抛出异常 可以看到 ActivityResultRegistry 加入对于 ComponentActivity 的 lifeCycle 的观察,保证只有当此 ComponentActivity 处于可用状态时才会执行回调,不可用时自动注销 注册完毕后返回一个 ActivityResultLauncher 对象,可以看到我们传入其 launch 方法的 input 参数又传给了 ActivityResultRegistry 的 onLauch 方法
onLaunch 方法
@MainThread
public abstract < I , O > void onLaunch (
int requestCode,
@NonNull ActivityResultContract < I , O > contract,
@SuppressLint ( "UnknownNullness" ) I input,
@Nullable ActivityOptionsCompat options) ;
可以看到, onLaunch 是一个抽象方法,这时我们又想起了一段熟悉的代码
public final < I , O > ActivityResultLauncher < I > registerForActivityResult (
@NonNull ActivityResultContract < I , O > contract,
@NonNull ActivityResultCallback < O > callback) {
return registerForActivityResult ( contract, mActivityResultRegistry, callback) ;
}
这个 mActivityResultRegistry 不正是 ComponentActivity 持有的 ActivityResultRegistry 的实现类吗,让我们来看看他是怎么来定义 onLaunch 的,来人啊,上代码
private final ActivityResultRegistry mActivityResultRegistry = new ActivityResultRegistry ( ) {
@Override
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) ;
if ( synchronousResult != null ) {
new Handler ( Looper . getMainLooper ( ) ) . post ( new Runnable ( ) {
@Override
public void run ( ) {
dispatchResult ( requestCode, synchronousResult. getValue ( ) ) ;
}
} ) ;
return ;
}
Intent intent = contract. createIntent ( activity, input) ;
Bundle optionsBundle = null ;
if ( intent. getExtras ( ) != null && intent. getExtras ( ) . getClassLoader ( ) == null ) {
intent. setExtrasClassLoader ( activity. getClassLoader ( ) ) ;
}
if ( intent. hasExtra ( EXTRA_ACTIVITY_OPTIONS_BUNDLE) ) {
optionsBundle = intent. getBundleExtra ( EXTRA_ACTIVITY_OPTIONS_BUNDLE) ;
intent. removeExtra ( EXTRA_ACTIVITY_OPTIONS_BUNDLE) ;
} else if ( options != null ) {
optionsBundle = options. toBundle ( ) ;
}
if ( ACTION_REQUEST_PERMISSIONS. equals ( intent. getAction ( ) ) ) {
String [ ] permissions = intent. getStringArrayExtra ( EXTRA_PERMISSIONS) ;
if ( permissions == null ) {
permissions = new String [ 0 ] ;
}
ActivityCompat . requestPermissions ( activity, permissions, requestCode) ;
} else if ( ACTION_INTENT_SENDER_REQUEST. equals ( intent. getAction ( ) ) ) {
IntentSenderRequest request =
intent. getParcelableExtra ( EXTRA_INTENT_SENDER_REQUEST) ;
try {
ActivityCompat . startIntentSenderForResult ( activity, request. getIntentSender ( ) ,
requestCode, request. getFillInIntent ( ) , request. getFlagsMask ( ) ,
request. getFlagsValues ( ) , 0 , optionsBundle) ;
} catch ( final IntentSender. SendIntentException e) {
new Handler ( Looper . getMainLooper ( ) ) . post ( new Runnable ( ) {
@Override
public void run ( ) {
dispatchResult ( requestCode, RESULT_CANCELED,
new Intent ( ) . setAction ( ACTION_INTENT_SENDER_REQUEST)
. putExtra ( EXTRA_SEND_INTENT_EXCEPTION, e) ) ;
}
} ) ;
}
} else {
ActivityCompat . startActivityForResult ( activity, intent, requestCode, optionsBundle) ;
}
}
} ;
终于,在这里看到了许许多多熟悉的面孔,1~4就不再介绍了,他们正如我们之前所猜想的流程那样定义在 onLaunch 方法中 我们注意到 getSynchronousResult 的结果是通过 ActivityResultRegistry 的 dispatchResult 方法传递出去的,那么这个方法是干啥的
dispatchResult 方法
在此之前,我们先来看看 ComponentActivity 中的 onActivityResult 回调
@CallSuper
@Override
@Deprecated
protected void onActivityResult ( int requestCode, int resultCode, @Nullable Intent data) {
if ( ! mActivityResultRegistry. dispatchResult ( requestCode, resultCode, data) ) {
super . onActivityResult ( requestCode, resultCode, data) ;
}
}
可以看到他也用了 dispatchResult 方法将结果传递出去,现在我们再来看 dispatchResult 的代码
@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 ;
}
我们可以看到,如果是没通过 registerForActivityResult 方法注册过的操作结果那么就让他接着回到 ComponentActivity 父类的 onActivityResult 回调,否则将结果传入 doDispatch 方法中
doDispatch 方法
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 {
mParsedPendingResults. remove ( key) ;
mPendingResults. putParcelable ( key, new ActivityResult ( resultCode, data) ) ;
}
}
和我们设想的一样,最终注册的操作的结果进入了 doDispatch 方法中,经由 parseResult 方法处理后传入了 callback.onActivityResult 回调(我们的Lambda表达式),就这样我们走完了一整个流程
其他
细心的你会发现,在上面 mActivityResultRegistry 的 onLaunch 方法的 注释5. 处调用的并不是上面的 dispatchResult 方法,而是另一个重载方法
@MainThread
public final < O > boolean dispatchResult ( int requestCode,
@SuppressLint ( "UnknownNullness" ) O result) {
String key = mRcToKey. get ( requestCode) ;
if ( key == null ) {
return false ;
}
mLaunchedKeys. remove ( key) ;
CallbackAndContract < ? > callbackAndContract = mKeyToCallback. get ( key) ;
if ( callbackAndContract == null || callbackAndContract. mCallback == null ) {
mPendingResults. remove ( key) ;
mParsedPendingResults. put ( key, result) ;
} else {
@SuppressWarnings ( "unchecked" )
ActivityResultCallback < O > callback =
( ActivityResultCallback < O > ) callbackAndContract. mCallback;
callback. onActivityResult ( result) ;
}
return true ;
}
看来逻辑和另一个 dispatchResult 方法差不多,不过这里就不用再调用 doDispatch 方法了,直接回调 callback.onActivityResult 细心的你又发现, ActivityResultRegistry 还有另一个 register 方法
@NonNull
public final < I , O > ActivityResultLauncher < I > register (
@NonNull final String key,
@NonNull final ActivityResultContract < I , O > contract,
@NonNull final ActivityResultCallback < O > callback)
我们可以看到,他不需要 LifecycleOwner 参数,这意味着我们可以在任何时刻调用这个 register 方法,但也意味着我们需要手动对我们 register 的操作进行 unregister
至此,我们就已经了解了 registerForActivityResult 中的绝大部分重要内容了