很多开发者对onActivityResult
抱怨已久:需要定义resultCode
和requestCode
,使用繁琐且容易出错。现在通过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))
}
}
}
省掉了烦人的resultCode
和requestCode
,代码更优雅
其他场景
看几个常见场景中如何使用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