告别onActivityResult,拥抱ActivityResultContract

告别onActivityResult,拥抱ActivityResultContract_第1张图片
很多开发者对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,代码更优雅
告别onActivityResult,拥抱ActivityResultContract_第2张图片

其他场景


看几个常见场景中如何使用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之一:
告别onActivityResult,拥抱ActivityResultContract_第3张图片
当然除以上预置的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

你可能感兴趣的:(Android,android)