告别onActivityResult,拥抱ActivityResultContract
16lz
2021-01-25
很多开发者对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" orimplementation "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
更多相关文章
- 一款常用的 Squid 日志分析工具
- GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
- RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
- Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
- 用Preferences,通过xml文件跳转到另一个Activity
- Android(安卓)Mediascanner实现机制
- Android(安卓)Logcat 报错:Could not create the view: For input
- Android原生工程配置导入uni-app项目-混合开发
- android 如何调用WPS显示工作文件