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

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

ActivityResultContract相关实现


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
                }
            }
        });
发布了116 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/vitaviva/article/details/105014966