You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用registerForActivityResult在独立类接收Activity结果及空指针排查

问题根因

空指针是Lifecycle事件触发顺序不匹配导致的:

  • 你在BiometricFragmentActivity的onCreate方法中,先调用getLifecycle().addObserver(mObserver),之后立刻执行mObserver.openBiometricSettings()
  • 但DefaultLifecycleObserver的onCreate回调,要等宿主BiometricFragmentActivity的onCreate方法执行完成后才会被调度,你调用openBiometricSettings的时候,mLauncher还没完成初始化,自然是空值。
修复方案

两种可行方案按需选择即可:

方案1:延迟调用跳转逻辑,等Observer初始化完成后触发

修改观察者类,新增标记位保存跳转需求,初始化完成后再执行跳转:

public class BiometricFragmentActivityLifecycleObserver implements DefaultLifecycleObserver {
    private final ActivityResultRegistry mRegistry;
    private ActivityResultLauncher<Intent> mLauncher;
    // 新增标记位,保存是否需要跳转设置页
    private boolean mNeedOpenSettings = false;

    BiometricFragmentActivityLifecycleObserver(@NonNull ActivityResultRegistry registry) {
        mRegistry = registry;
    }

    public void onCreate(@NonNull LifecycleOwner owner) {
        mLauncher = BiometricFragmentActivity.instance.registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == AppCompatActivity.RESULT_OK) {
                        BiometricManager biometricManagerRetry = BiometricManager.from(BiometricFragmentActivity.instance);
                        if(biometricManagerRetry.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS){
                            BiometricUtils.canAuthenticate = true;
                        }else{
                            BiometricUtils.canAuthenticate = false;
                        }
                    }else{
                        BiometricUtils.canAuthenticate = false;
                    }
                }
        );
        // 初始化完成后判断是否需要跳转
        if(mNeedOpenSettings){
            openBiometricSettings();
        }
    }

    // 新增设置是否需要跳转的方法
    public void setNeedOpenSettings(boolean needOpen) {
        this.mNeedOpenSettings = needOpen;
        // 如果mLauncher已经初始化完成,直接跳转
        if(mLauncher != null && needOpen){
            openBiometricSettings();
        }
    }


    public void openBiometricSettings(){
        final Intent enrollIntent;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL);
            enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
                    BIOMETRIC_STRONG | DEVICE_CREDENTIAL);
        }else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && Build.VERSION.SDK_INT < Build.VERSION_CODES.R){
            enrollIntent = new Intent(Settings.ACTION_FINGERPRINT_ENROLL);
        }else{
            enrollIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
        }
        mLauncher.launch(enrollIntent);
    }
}

修改Activity的onCreate逻辑,把直接调用open的逻辑换成设置标记位:

@Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.TransparentActivityTheme);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.biometric_fragment_activity);
    instance = this;
    viewGroupContent = findViewById(android.R.id.content);
    mObserver = new BiometricFragmentActivityLifecycleObserver(instance.getActivityResultRegistry());
    getLifecycle().addObserver(mObserver);
    NavigationUtils.mListener.onCreated();

    if(BiometricUtils.canAuthenticate && BiometricUtils.needEnrollment){
        // 不再直接调用open,而是设置标记位
        mObserver.setNeedOpenSettings(true);
    }
}

方案2:直接在Activity中初始化Launcher,规避生命周期时序问题

不需要把Launcher初始化放到Observer里,直接在Activity的onCreate中初始化即可,逻辑更简单:

public class BiometricFragmentActivity extends FragmentActivity {
    public static FragmentActivity instance;
    public static ViewGroup viewGroupContent;
    private ActivityResultLauncher<Intent> mBiometricEnrollLauncher;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.TransparentActivityTheme);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.biometric_fragment_activity);
        instance = this;
        viewGroupContent = findViewById(android.R.id.content);
        // 直接初始化Launcher
        mBiometricEnrollLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == AppCompatActivity.RESULT_OK) {
                        BiometricManager biometricManagerRetry = BiometricManager.from(this);
                        if(biometricManagerRetry.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS){
                            BiometricUtils.canAuthenticate = true;
                        }else{
                            BiometricUtils.canAuthenticate = false;
                        }
                    }else{
                        BiometricUtils.canAuthenticate = false;
                    }
                }
        );
        NavigationUtils.mListener.onCreated();

        if(BiometricUtils.canAuthenticate && BiometricUtils.needEnrollment){
            openBiometricSettings();
        }
    }

    private void openBiometricSettings(){
        final Intent enrollIntent;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL);
            enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
                    BIOMETRIC_STRONG | DEVICE_CREDENTIAL);
        }else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && Build.VERSION.SDK_INT < Build.VERSION_CODES.R){
            enrollIntent = new Intent(Settings.ACTION_FINGERPRINT_ENROLL);
        }else{
            enrollIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
        }
        mBiometricEnrollLauncher.launch(enrollIntent);
    }
}
额外注意事项
  • 不要用静态变量持有Activity实例,会导致内存泄漏,你代码里public static FragmentActivity instance;的写法存在隐患,建议通过LifecycleOwner或者Context参数传递上下文,不要用静态变量存储Activity实例。
  • 使用Activity Result API时,必须在Activity走到CREATED状态之前完成Launcher的注册,否则会抛出异常,上述两种修复方案都符合这个要求。

内容的提问来源于stack exchange,提问作者Víctor Martín

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:06:01