赞
踩
在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 方法简化了回调的流程,在开发中更合理的处理回调。
调用 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."); } ... }
为了避免如上异常,正确用法如下:
@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));
});
}
在非 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 正确的调用方式。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。