深入理解ActivityResultContracts--替代startActivityForResult的新玩法

104 篇文章 29 订阅

本文使用的alpha版本API已经过期,想了解最新API的使用,请移步
深入理解Result API:ActivityResultContract的实现原理

ActivityResultContractActivity 1.2.0-alpha02Fragment 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
                }
            }
        });
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Android Studio中,替代`startActivityForResult`的方法有很多。你可以使用的`ActivityResultLauncher`和`IntentBuilder`库,以及`startActivity()`方法。 以下是一些替代`startActivityForResult`的常用方法: 1. 使用`ActivityResultLauncher`: * `getActivityResultLauncher(Context, IntentResult): ActivityResultLauncher`:这个方法允许你启动一个Activity并获取其结果。 * `getActivityResultReceiver(Context, Intent, PendingIntent.OnActivityResult): ActivityResultReceiver`:这个方法允许你启动一个Activity并传递一个结果给其他Activity。 2. 使用`IntentBuilder`库: * `IntentBuilder(Context): IntentBuilder`:使用这个类可以更方便地构建和传递Intent。 * `setClass(Context, Class)`:这个方法可以用来设置启动一个Activity的目标类。 * `addFlags(int)`:可以添加额外的Intent标志。 3. 使用`startActivity()`方法: * `startActivity(Context, Intent)`:这个方法可以用来启动一个Activity,但没有等待结果的功能。 下面是一个使用`IntentBuilder`库替代`startActivityForResult`的示例代码: ```kotlin // 创建一个IntentBuilder对象 val intentBuilder = IntentBuilder<MainActivity>() // 设置启动的Activity类 .setClass(this, MainActivity::class.java) // 添加额外的Intent标志,例如添加数据传递到另一个Activity .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) // 构建Intent并启动Activity .build() // 使用startActivity()方法启动Activity,无需等待结果 .start() ``` 请注意,这只是一个简单的示例,具体使用方法可能因实际情况而异。根据你的需求,选择适合的方法来替代`startActivityForResult`。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值