registerForActivityResult 方法介绍
1.1 过时的 startActivityForResult 方法
在API 29 之前的版本中,跳转 Activity 获取返回结果使用的是startActivityForResult 方法,而 startActivityForResult 方法在API 29 中废弃,为过时方法,而谷歌推出 registerForActivityResult 方法来替代。
startActivityForResult 方法用法如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
findViewById(R.id.btn_start).setOnClickListener(v -> {
startActivityForResult(new Intent(MainActivity.this, SecondActivity.class), 1);
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1 && resultCode == RESULT_OK) {
}
}
这种方式需要重写 onActivityResult 方法,然后判断 requestCode 和 resultCode 的方式处理回调,流程麻烦了一点且不合时宜。而 registerForActivityResult 方法简化了回调的流程,在开发中更合理的处理回调。
1.2 registerForActivityResult 错误的调用方式
调用 registerForActivityResult 方法时,可能有人会像下面的错误方式在点击事件中调用:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
findViewById(R.id.btn_start).setOnClickListener(v -> {
ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
}
});
activityResultLauncher.launch(new Intent(MainActivity.this, SecondActivity.class));
});
}
这样的调用方式会出现如下报错:
java.lang.IllegalStateException: LifecycleOwner com.example.testapp.MainActivity@f5102ac is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
LifecycleOwners 必须在状态为 STARTED 之前调用,LifecycleOwners 也就是 Activity,意思为 registerForActivityResult 方法需要在 onCreate 和 onStart 或者 onRestart 的生命周期之间调用,在其他生命周期调用包含点击事件中调用会出现抛出异常。
在 registerForActivityResult 方法调用栈中,ActivityResultRegistry 的 register 方法会检查当前的 lifecycle 状态是否为 STARTED 之前的状态,不符合则抛出异常。
//ActivityResultRegistry.java
@NonNull
public final <I, O> ActivityResultLauncher<I> register(
@NonNull final String key,
@NonNull final LifecycleOwner lifecycleOwner,
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultCallback<O> callback) {
Lifecycle lifecycle = lifecycleOwner.getLifecycle();
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.");
}
...
}
1.3 registerForActivityResult 正确的调用方式
为了避免如上异常,正确用法如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
}
});
findViewById(R.id.btn_start).setOnClickListener(v -> {
activityResultLauncher.launch(new Intent(MainActivity.this, SecondActivity.class));
});
}
registerForActivityResult 的封装
在非 onCreate 、onStart、onRestart 的生命周期方法回调中调用 registerForActivityResult 方法会跑吹异常,如果想在点击事件或者其他时序中调用 registerForActivityResult 方法,可以利用 Fragment 的创建周期实现对 registerForActivityResult 方法的调用。封装如下:
public class ActivityResultFragment extends Fragment {
private ActivityResultCallback<ActivityResult> mCallback;
private Intent mIntent;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (mCallback != null) {
mCallback.onActivityResult(result);
}
getParentFragmentManager().beginTransaction()
.remove(ActivityResultFragment.this)
.commitAllowingStateLoss();
});
if (mIntent != null) {
activityResultLauncher.launch(mIntent);
}
}
public static void launchActivityResult(FragmentManager fragmentManager, ActivityResultCallback<ActivityResult> callback, Intent intent) {
ActivityResultFragment fragment = new ActivityResultFragment();
fragment.setCallback(callback);
fragment.setIntent(intent);
fragmentManager.beginTransaction()
.add(fragment, "ActivityResultFragment")
.commitAllowingStateLoss();
}
private void setIntent(Intent intent) {
mIntent = intent;
}
private void setCallback(ActivityResultCallback<ActivityResult> callback) {
mCallback = callback;
}
@Override
public void onDestroy() {
mCallback = null;
super.onDestroy();
}
}
用法如下:
findViewById(R.id.btn_start).setOnClickListener(v -> {
ActivityResultFragment.launchActivityResult(getSupportFragmentManager(),
this, new Intent(MainActivity.this, SecondActivity.class));
});
如上即可在非 onCreate 、 onStart 或者 onRestart 之间调用 registerForActivityResult 方法。当然ActivityResultLauncher 的 launch 方法是可以正常在点击事件中调用的,如果嫌麻烦直接用上述最简单的方式进行调用:registerForActivityResult 正确的调用方式。