当前位置:   article > 正文

registerForActivityResult方法介绍以及封装,解决点击事件中无法调用问题_fragment registerforactivityresult

fragment registerforactivityresult

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

        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这种方式需要重写 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));
        });
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这样的调用方式会出现如下报错:

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

用法如下:

        findViewById(R.id.btn_start).setOnClickListener(v -> {
            ActivityResultFragment.launchActivityResult(getSupportFragmentManager(),
                    this, new Intent(MainActivity.this, SecondActivity.class));
        });
  • 1
  • 2
  • 3
  • 4

如上即可在非 onCreate 、 onStart 或者 onRestart 之间调用 registerForActivityResult 方法。当然ActivityResultLauncher 的 launch 方法是可以正常在点击事件中调用的,如果嫌麻烦直接用上述最简单的方式进行调用:registerForActivityResult 正确的调用方式

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/231695
推荐阅读
相关标签
  

闽ICP备14008679号