registerForActivityResult(下)
相关库
~~startActivityForResult~~
被标注弃用,推荐使用registerForActivityResult
,查看源码发现其实就是对startActivityForResult
和onActivityResult
的封装。
整体代码比较简单,关注几个关键方法即可。
ActivityResultRegistry#register
调用registerForActivityResult
方法时,会生成一个key值并调用ActivityResultRegistry
的register
。在register
方法中会将key值缓存起来,并生成一个requestCode,这个code就是startActivityForResult
所用需要用到的。
private int registerKey(String key) {
Integer existing = mKeyToRc.get(key);
if (existing != null) {
return existing;
}
//生成requestCode
int rc = generateRandomNumber();
//将requestCode和key值绑定,并缓存起来
bindRcKey(rc, key);
return rc;
}
在经过一些生命周期判断,异常判断,最后返回一个ActivityResultLauncher
对象,这个对象就是调用registerForActivityResult
的返回值
return new ActivityResultLauncher() {
@Override
public void launch(I input, @Nullable ActivityOptionsCompat options) {
//缓存key,获取code
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 getContract() {
return contract;
}
};
可以看到当我们调用launch
方法时,实际上拿到requestcode,传递给onLaunch
回调方法,这个方法其实启动activity的实现,
ActivityResultRegistry#onLaunch
ComponentActivity中实现了ActivityResultRegistry的onLaunch
方法,该方法最终调用了(权限请求时,调用的是ActivityCompat.requestPermissions
)
ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
所以launch,最终调用的是startActivityForResult
ActivityResultCallback
前面梳理了activity的启动过程,接下来看看activity的数据回传结果是如果实现的吧。
前面知道内部仍然调用startActivityForResult
,所以回调我们直接查看onActivityResult
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
public final boolean dispatchResult(int requestCode, int resultCode, @Nullable Intent data) {
//通过code反找key
String key = mRcToKey.get(requestCode);
if (key == null) {
return false;
}
mLaunchedKeys.remove(key);
//通过key找到缓存的ActivityResultCallback,ActivityResultContract
doDispatch(key, resultCode, data, mKeyToCallback.get(key));
return true;
}
private void doDispatch(String key, int resultCode, @Nullable Intent data,
@Nullable CallbackAndContract callbackAndContract) {
if (callbackAndContract != null && callbackAndContract.mCallback != null) {
ActivityResultCallback callback = callbackAndContract.mCallback;
ActivityResultContract, O> contract = callbackAndContract.mContract;
//封装返回的数据,并调用callback,完成回调
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));
}
}
其中ActivityResultContract
功能很简单,就是对我们传入intent,和返回的intent进行处理封装的。
使用上的不便
功能实现上是ok,但是使用时有一个不方便的地方就是registerForActivityResult
对调用时所在的生命周期有要求。
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.");
}
上面的异常就限制了我必须在started状态之前就提前定义并调用registerForActivityResult
方法,等到需要启动时在调用launch
方法,并不能随用随调。
可以通过二次封装的形式达到随意调用。