registerForActivityResult(下)
相關(guān)庫
~~startActivityForResult~~
被標(biāo)注棄用,推薦使用registerForActivityResult
咖驮,查看源碼發(fā)現(xiàn)其實(shí)就是對startActivityForResult
和onActivityResult
的封裝边器。
整體代碼比較簡單,關(guān)注幾個關(guān)鍵方法即可托修。
ActivityResultRegistry#register
調(diào)用registerForActivityResult
方法時忘巧,會生成一個key值并調(diào)用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;
}
在經(jīng)過一些生命周期判斷际长,異常判斷,最后返回一個ActivityResultLauncher
對象兴泥,這個對象就是調(diào)用registerForActivityResult
的返回值
return new ActivityResultLauncher<I>() {
@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<I, ?> getContract() {
return contract;
}
};
可以看到當(dāng)我們調(diào)用launch
方法時,實(shí)際上拿到requestcode搓彻,傳遞給onLaunch
回調(diào)方法如绸,這個方法其實(shí)啟動activity的實(shí)現(xiàn),
ActivityResultRegistry#onLaunch
ComponentActivity中實(shí)現(xiàn)了ActivityResultRegistry的onLaunch
方法旭贬,該方法最終調(diào)用了(權(quán)限請求時怔接,調(diào)用的是ActivityCompat.requestPermissions
)
ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
所以launch,最終調(diào)用的是startActivityForResult
ActivityResultCallback
前面梳理了activity的啟動過程稀轨,接下來看看activity的數(shù)據(jù)回傳結(jié)果是如果實(shí)現(xiàn)的吧扼脐。
前面知道內(nèi)部仍然調(diào)用startActivityForResult
,所以回調(diào)我們直接查看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 <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;
//封裝返回的數(shù)據(jù),并調(diào)用callback靶端,完成回調(diào)
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進(jìn)行處理封裝的。
使用上的不便
功能實(shí)現(xiàn)上是ok脏榆,但是使用時有一個不方便的地方就是registerForActivityResult
對調(diào)用時所在的生命周期有要求猖毫。
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狀態(tài)之前就提前定義并調(diào)用registerForActivityResult
方法,等到需要啟動時在調(diào)用launch
方法须喂,并不能隨用隨調(diào)吁断。
可以通過二次封裝的形式達(dá)到隨意調(diào)用。