深入理解ActivityResultContracts--替代startActivityForResult的新玩法
ActivityResultContract
是 Activity 1.2.0-alpha02
和 Fragment 1.3.0-alpha02
中新追加的API,可以更加方便且typeSafe地处理startActivityForResult
。
如何使用
AppCompatActivity和Fragment中可以通过prepareCall()
创建launcher
,然后调用launch(intent)
进行startActivityForResult
//MainActivity.ktval intent = Intent(this, SecondActivity::class.java)val launcher: ActivityResultLauncher<Intent> = prepareCall( ActivityResultContracts.StartActivityForResult()) { activityResult: ActivityResult -> Log.d("MainActivity", activityResult.toString()) // D/MainActivity: ActivityResult{resultCode=RESULT_OK, data=Intent { (has extras) }}}fab.setOnClickListener { view -> launcher.launch(intent)}
//SecondActivity.ktclass SecondActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setResult(Activity.RESULT_OK, Intent().putExtra("my-data", "data")) finish() }}
ActivityResultContracts相关实现
StartActivityForResult
prepareCall()
中传入ActivityResultContracts.StartActivityForResult
的实例,它继承自 ActivityResultContract
// ActivityResultContracts.javapublic class ActivityResultContracts { private ActivityResultContracts() {}... public static class StartActivityForResult extends ActivityResultContract<Intent, ActivityResult> { @NonNull @Override public Intent createIntent(@NonNull Intent input) { return input; } @NonNull @Override public ActivityResult parseResult(int resultCode, @Nullable Intent intent) { return new ActivityResult(resultCode, intent); } }
当然替换为匿名类的写法也OK,如下
val launcher: ActivityResultLauncher<Intent> = prepareCall( // ** ↓ ** object : ActivityResultContract<Intent, ActivityResult>() { override fun createIntent(input: Intent): Intent { return input } override fun parseResult(resultCode: Int, intent: Intent?): ActivityResult { return ActivityResult(resultCode, intent) } } // ** ↑ **) { activityResult: ActivityResult -> Log.d("MainActivity", activityResult.toString()) // D/MainActivity: ActivityResult{resultCode=RESULT_OK, data=Intent { (has extras) }}}
通过ActivityResultContract的两个泛型参数约束startActivity的参数类型以及onActivityResult返回的结果类型
ActivityResultRegistry
prepareCall
内会调用ActivityResultRegistry.registerActivityResultCallback()
方法
@NonNull @Override public <I, O> ActivityResultLauncher<I> prepareCall( @NonNull ActivityResultContract<I, O> contract, @NonNull ActivityResultCallback<O> callback) { return prepareCall(contract, mActivityResultRegistry, callback); } @NonNull @Override public <I, O> ActivityResultLauncher<I> prepareCall( @NonNull final ActivityResultContract<I, O> contract, @NonNull final ActivityResultRegistry registry, @NonNull final ActivityResultCallback<O> callback) { return registry.registerActivityResultCallback( "activity_rq#" + mNextLocalRequestCode.getAndIncrement(), this, contract, callback); } @NonNull public ActivityResultRegistry getActivityResultRegistry() { return mActivityResultRegistry; }
当然Activity也可以脱离prepareCall直接调用activityResultRegistry,如下
// ** ↓ **val launcher: ActivityResultLauncher<Intent> = activityResultRegistry .registerActivityResultCallback( "activity_rq#0", // 此数字在调用时保持Autoincrement // ** ↑ ** object : ActivityResultContract<Intent, ActivityResult>() { override fun createIntent(input: Intent): Intent { return input } override fun parseResult(resultCode: Int, intent: Intent?): ActivityResult { return ActivityResult(resultCode, intent) } } ) { activityResult: ActivityResult -> Log.d("MainActivity", activityResult.toString()) // D/MainActivity: ActivityResult{resultCode=RESULT_OK, data=Intent { (has extras) }} }
registerActivityResultCallback()
会向持有ActivityResultRegistory
的HashMap执行put操作,记录ActivityResultContract
ComponentActivity相关实现
Activity中持有ActivityResultRegistry,ActivityResultRegistry通过HashMap管理ActivityResultContract和ActivityResultCallback。HashMap的Key形式如下:
"activity_rq#" + mNextLocalRequestCode.getAndIncrement()
还需要requestCode吗
以往,onActivityResult需要通过requestCode
来识别是哪个startActivityForResult的返回,现在可以通过AutoIncrement来管理。而且当进程被杀时onSaveInstanceState
会自动保存requestCode和ActivityResultRegistry的key的pair对,当onActivityResult返回rc时,可以通过对应关系找到key,然后找到ActivityResultCallback
//ActivityResultRegistry.javaprivate int registerKey(String key) { Integer existing = mKeyToRc.get(key); if (existing != null) { return existing; } int rc = mNextRc.getAndIncrement(); bindRcKey(rc, key); return rc; }
Fragment相关实现
Fragment.prepareCall()的实现中,在ON_CREATE的时候,会调用getActivity().getActivityResultRegistry().registerActivityResultCallback
//Fragment.javapublic <I, O> ActivityResultLauncher<I> prepareCall( @NonNull final ActivityResultContract<I, O> contract, @NonNull final ActivityResultCallback<O> callback) {... getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner, @NonNull Lifecycle.Event event) { if (Lifecycle.Event.ON_CREATE.equals(event)) { ref.set(getActivity() .getActivityResultRegistry() // 这里registerActivityResultCallback .registerActivityResultCallback( key, Fragment.this, contract, callback)); } } }); return new ActivityResultLauncher<I>() { @Override public void launch(I input) {... } }; }
registerActivityResultCallback虽然将framgent实例注入到上级持有的HashMap,但是在ON_DESTROY的时候会进行对应的后处理,所以不必担心造成内存泄漏
//ActivityResultRegistry.javalifecycle.addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner, @NonNull Lifecycle.Event event) { if (Lifecycle.Event.ON_DESTROY.equals(event)) { unregisterActivityResultCallback(key);//后处理避免leak } } });
更多相关文章
- ARouter 源码学习之Compiler
- Android之intent传值的三种方法
- android毛玻璃背景简单实现
- Android(安卓)studio App开发 SQLite数据的使用
- Android:Date、String、Long三种日期类型之间的相互转换
- Android(安卓)EventLog简介
- Android中双击返回键退出应用实例代码
- Android(安卓)Glide传Context引发的非法参数异常那些小坑
- Android设置EditText输入类型:setInputType()方法和android:input