本文使用的alpha版本API已经过期,想了解最新API的使用,请移步
深入理解Result API:ActivityResultContract的实现原理
ActivityResultContract
是 Activity 1.2.0-alpha02
和 Fragment 1.3.0-alpha02
中新追加的API,可以更加方便且typeSafe地处理startActivityForResult
。
如何使用
AppCompatActivity和Fragment中可以通过prepareCall()
创建launcher
,然后调用launch(intent)
进行startActivityForResult
//MainActivity.kt
val 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.kt
class 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.java
public 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.java
private 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.java
public <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.java
lifecycle.addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner,
@NonNull Lifecycle.Event event) {
if (Lifecycle.Event.ON_DESTROY.equals(event)) {
unregisterActivityResultCallback(key);//后处理避免leak
}
}
});