Activity Result API 使用与源码分析(1)

override fun onCreate(owner: LifecycleOwner) {

getContent = registry.register(“key”, owner, ActivityResultContracts.GetContent(),

ActivityResultCallback { log(it) })

}

fun selectImage(){

getContent.launch(“image/*”)

}

}

二,源码


使用版本activity-ktx:1.2.2,fragment-ktx:1.3.3

1.register

registerForActivityResult方法最终会调用ActivityResultRegistryregister方法,通过不同的key生成一个唯一的requestCode,把这个requestCode保存下来,在结果返回时使用。通过Lifecycle添加一个观察者,监听Activity的ON_START,ON_STOP,ON_DESTROY事件。在ON_START事件到来时,会从mPendingResults这个bundle对象中通过key获取结果,如果有结果,则将结果回调到调用者处。ON_STOP事件则是移除这个key对应的CallbackAndContract对象,ON_DESTROY事件移除这个key对应的所有信息。最后返回ActivityResultLauncher对象给调用者使用。

public final <I, O> ActivityResultLauncher register(

@NonNull final String key,

@NonNull final LifecycleOwner lifecycleOwner,

@NonNull final ActivityResultContract<I, O> contract,

@NonNull final ActivityResultCallback callback) {

Lifecycle lifecycle = lifecycleOwner.getLifecycle();

//每个请求的key也不一样,根据key生成一个唯一的requestCode

final int requestCode = registerKey(key);

//把lifecycle和observer统一封装到LifecycleContainer中

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);

}

//从bundle中获取结果

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);//stop时移除

} else if (Lifecycle.Event.ON_DESTROY.equals(event)) {

unregister(key);//destory时注销

}

}

};

//添加观察者

lifecycleContainer.addObserver(observer);

mKeyToLifecycleContainers.put(key, lifecycleContainer);

//返回ActivityResultLauncher对象

return new ActivityResultLauncher() {

@Override

public void launch(I input, @Nullable ActivityOptionsCompat options) {

mLaunchedKeys.add(key);

//ActivityResultRegistry的onLaunch,抽象方法,在ComponentActivity内实现

onLaunch(requestCode, contract, input, options);

}

public void unregister() {

ActivityResultRegistry.this.unregister(key);

}

public ActivityResultContract<I, ?> getContract() {

return contract;

}

};

}

2.launch

ActivityResultRegistryonLaunch是一个抽象方法,在ComponentActivity内实现。首先会检查contract是否能获取同步结果,如果能,则直接分发处理。比如权限申请,我前面已经获取了权限,直接可以通过getSynchronousResult查询是否有权限。有直接返回true,不再通过requestPermissions去做申请权限。

在通过contract获取Intent,按Intent分为三种情况处理,第一种,权限申请,通过requestPermissions去申请权限,第二种处理INTENT_SENDER,和startIntentSenderForResult类似。第三种,处理其它问题,通过startActivityForResult启动Activity

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 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 intent = contract.createIntent(activity, input);

Bundle optionsBundle = null;

// If there are any extras, we should defensively set the classLoader

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())) {

// requestPermissions path

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())) {

//处理StartIntentSenderForResult

IntentSenderRequest request =

intent.getParcelableExtra(EXTRA_INTENT_SENDER_REQUEST);

try {

// startIntentSenderForResult path

ActivityCompat.startIntentSenderForResult(activity, request.getIntentSender(),

requestCode, request.getFillInIntent(), request.getFlagsMask(),

request.getFlagsValues(), 0, optionsBundle);

} catch (final IntentSender.SendIntentException e) {

}

} else {

//其它普通问题启动Activity

ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);

}

}

3.结果回调

ComponentActivity中,onActivityResult和onRequestPermissionsResult方法会先被ActivityResultRegistry的dispatchResult方法拦截,如果它能处理,则不再调用Activity的方法。

dispatchResult会调用doDispatch来处理结果,这有两种情况,通过keymKeyToCallback中获取callbackAndContract对象,如果不为空,则直接回调结果。比如权限申请,不会走ON_STOP事件,mKeyToCallback不会被清除,这里就不会为空。如果为空则把结果放到mPendingResults这个Bundle对象中,和前面的ON_START事件对应起来,从mPendingResults取出结果,回调结果。

-ComponentActivity.java

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {

if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {

super.onActivityResult(requestCode, resultCode, data);

}

}

public void onRequestPermissionsResult(

int requestCode,

@NonNull String[] permissions,

@NonNull int[] grantResults) {

if (!mActivityResultRegistry.dispatchResult(requestCode, Activity.RESULT_OK, new Intent()

.putExtra(EXTRA_PERMISSIONS, permissions)

.putExtra(EXTRA_PERMISSION_GRANT_RESULTS, grantResults))) {

if (Build.VERSION.SDK_INT >= 23) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

}

}

}

  • ActivityResultRegistry.java

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;

}

private void doDispatch(String key, int resultCode, @Nullable Intent data,

@Nullable CallbackAndContract callbackAndContract) {

callbackAndContract不为空则直接回调即可

if (callbackAndContract != null && callbackAndContract.mCallback != null) {

ActivityResultCallback callback = callbackAndContract.mCallback;

ActivityResultContract<?, O> contract = callbackAndContract.mContract;

callback.onActivityResult(contract.parseResult(resultCode, data));

} else {把结果放到mPendingResults中。等会调用。

// Remove any parsed pending result

mParsedPendingResults.remove(key);

// And add these pending results in their place

mPendingResults.putParcelable(key, new ActivityResult(resultCode, data));

}

}

学习分享,共勉

Android高级架构师进阶之路

题外话,我在阿里工作多年,深知技术改革和创新的方向,Android开发以其美观、快速、高效、开放等优势迅速俘获人心,但很多Android兴趣爱好者所需的进阶学习资料确实不太系统,完整。今天我把我搜集和整理的这份学习资料分享给有需要的人

  • Android进阶知识体系学习脑图

  • Android进阶高级工程师学习全套手册

  • 对标Android阿里P7,年薪50w+学习视频

  • 大厂内部Android高频面试题,以及面试经历


《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
。今天我把我搜集和整理的这份学习资料分享给有需要的人

  • Android进阶知识体系学习脑图

[外链图片转存中…(img-HH26SXlf-1714478039668)]

  • Android进阶高级工程师学习全套手册

[外链图片转存中…(img-06AMPiRR-1714478039668)]

  • 对标Android阿里P7,年薪50w+学习视频

[外链图片转存中…(img-SJN9GWma-1714478039669)]

  • 大厂内部Android高频面试题,以及面试经历

[外链图片转存中…(img-tq0ZWSzn-1714478039669)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值