ResultAPI:告别onActivityResult,拥抱ActivityResultContract

在这里插入图片描述
很多开发者对onActivityResult抱怨已久:需要定义resultCoderequestCode,使用繁琐且容易出错。现在通过KTX新发布的ActivityResultContract可以很多好地解决上述烦恼

基本使用


Before

传统的onActivityResult写法

class MainActivity : AppCompatActivity() {

    companion object {
        private const val REQUEST_CODE = 1234
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_open.setOnClickListener {
            startActivityForResult(
                    SecondActivity.createIntent(this),
                    REQUEST_CODE
            )
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Log.d("MainActivity", "requestCode: $requestCode, resultCode: $resultCode, data: $data")
    }
}

SecondActivity需要finish之前需要setResult

setResult(Activity.RESULT_OK, intent)
finish()

After

引入gradle

implementation "androidx.activity:activity-ktx:$latest_vsersion"
  or
implementation "androidx.fragment:fragment-ktx:$latest_vsersion"
class MainActivity : AppCompatActivity() {

    private val launcher: ActivityResultLauncher<Intent> =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
                Log.d("MainActivity", activityResult.toString())
            }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_open.setOnClickListener {
            launcher.launch(SecondActivity.createIntent(this))
        }
    }
}

省掉了烦人的resultCoderequestCode,代码更优雅
在这里插入图片描述

其他场景


看几个常见场景中如何使用ActivityResultContract:

选择文件

打开文件管理器选择图片并返回uri,首先看一下基于onActivityResult的实现:

class MainActivity : AppCompatActivity() {
    companion object {
        private const val REQUEST_CODE_CHOOSER = 1234
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_get_content.setOnClickListener {
            startActivityForResult(
                    Intent(Intent.ACTION_GET_CONTENT).apply {
                        addCategory(Intent.CATEGORY_OPENABLE)
                        type = "image/*"
                    },
                    REQUEST_CODE_CHOOSER
            )
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE_CHOOSER && resultCode == Activity.RESULT_OK) {
            Log.d("MainActivity", "uri: ${data?.data}")
        }
    }
}

基于ActivityResultContracts实现后:

class MainActivity : AppCompatActivity() {

    private val launcher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
        Log.d("MainActivity", "uri: $uri")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_get_content.setOnClickListener {
            launcher.launch("image/*")
        }
    }
}

ActivityResultContracts.GetContent是系统预置的几种Contracts之一:
在这里插入图片描述
当然除以上预置的Contracts以外,也可以通过继承ActivityResultContracts自定义自己的Contracts

权限请求

requestPermission与startActivityForResult的过程比较类似:

//权限请求
ActivityCompat.requestPermissions(this, arrayOf(WRITE_EXTERNAL_STORAGE), REQUEST_CODE)
//返回结果
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    if (requestCode == REQUEST_CODE) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "result: granted", Toast.LENGTH_LONG).show()
        }
        return
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

基于ActivityResultContract的实现:

// 设置回调
private val launcher = registerForActivityResult(RequestPermission()) {
    if (it) {
        Toast.makeText(this, "result: granted", Toast.LENGTH_LONG).show()
    }
}
// 请求权限
launcher.launch(WRITE_EXTERNAL_STORAGE)

实现原理


关于ActivityResultContract的原理比较简单,有兴趣的同学可以参考深入理解ActivityResultContracts

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

fundroid

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

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

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

打赏作者

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

抵扣说明:

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

余额充值