之前在 Jetpack Compose中的导航路由 里简单的提到了从 Compose
导航到其他 Activity
页面的方式,对于不带返回结果的则就是跟以前一样简单的启动Activity
的代码,而如果是startActivityForResult
方式的,需要使用带回调的方式去启动,那么在以前,我们要么是使用三方库,要么是自己封装一个简单的库来使用 (至于背后原理也不是什么新鲜事了) 。
后来研究了一下,在Compose
中startActivityForResult
也有了新的姿势,要理解Compose
中startActivityForResult
的姿势,这还得从androidx
的startActivityForResult
的姿势说起,因为Compose
就是在androidx
的基础上利用其API简单封装了一下而已。
倒也不是说以前的不能用了,毕竟有系统自带的,谁还去用第三方的呀,用第三方的还得导入一个依赖库不是,能少依赖三方的就尽量少依赖吧。
androidx之后如何正确的startActivityForResult
如何使用
如果是在Activity
或Fragment
内部使用的话,直接调用registerForActivityResult
方法即可。
例如,选择文件:
val launcher = registerForActivityResult(ActivityResultContracts.GetContent()) {
uri ->
uri?.apply {
showToast(uri.toString()) }
}
launcher.launch("image/*")
ActivityResultContracts.GetContent()
的方式获取文件launch
时需要通过指定 mime type
来过滤文件类型, 例如 image/*
,这会打开系统自带的一个文件选择器供你选择文件。
录制视频:
val outVideoFile = File(externalCacheDir, "/${
System.currentTimeMillis()}.mp4")
val videoUri = FileProvider.getUriForFile(this, "${
packageName}.provider", outVideoFile)
val launcher = registerForActivityResult(ActivityResultContracts.CaptureVideo()) {
isSuccess ->
if (isSuccess) {
showToast(outVideoFile.path)
}
}
launcher.launch(videoUri)
拍照:
val outPictureFile = File(externalCacheDir, "/${
System.currentTimeMillis()}.jpeg")
val pictureUri = FileProvider.getUriForFile(this, "${
packageName}.provider", outPictureFile)
val launcher = registerForActivityResult(ActivityResultContracts.TakePicture()) {
isSuccess ->
if (isSuccess) {
showToast(outPictureFile.path)
}
}
launcher.launch(pictureUri)}
这两种方式需要指定Uri
, 这个Uri
获取有点费劲,需要先进行FileProvider配置,不过配置好就很方便了。(如果你的minSdk配置的是29,那么需要另外配置,可自行查阅相关资料,不过国内基本不会兼容这么高的版本,一般minSdk配置的会是21)
自己的内部业务Activity之间的跳转:
// MainActivity.kt
val target = Intent(this, OtherActivity::class.java).apply {
putExtra("name", "张三")
putExtra("uid", 123)
}
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
activityResult ->
activityResult.data?.apply {
val name = getStringExtra("name")
name?.let {
showToast(it) }
}
}
launcher.launch(target)
// OtherActivity.kt
class OtherActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val name = intent.getStringExtra("name")
val uid = intent.getIntExtra("uid", -1)
setContent {
MyComposeApplicationTheme {
Surface(modifier = Modifier.fillMaxSize()) {
Column {
Text("name: $name fromCompose: $fromCompose uid: $uid", fontSize = 20.sp)
Button(onClick = {
val data = Intent().apply {
putExtra("name", "小明") }
setResult(RESULT_OK, data)
finish()
}) {
Text("back with result") }
}
}
}
}
}
}
在registerForActivityResult
的回调接口lambda中,仍然可以像以前那样使用activityResult.resultCode == RESULT_OK
来判断是正常返回了,还是取消操作。
在Activity/Fragment以外的类中使用:
class MyLifecycleObserver(private val registry : ActivityResultRegistry) : DefaultLifecycleObserver {
lateinit var getContent : ActivityResultLauncher<String>
override fun onCreate(owner: LifecycleOwner) {
getContent = registry.register("key", owner, ActivityResultContracts.GetContent()) {
uri ->
// Handle the returned Uri
}
}
fun selectImage() {
getContent.launch("image/*")
}
}
很简单,将代码移到一个LifecycleObserver
的实现类中即可,然后在Activity/Fragment
中将这个LifecycleObserver
的实现类的观察者对象添加到其本身的lifecycle
中即可。
class MyFragment : Fragment(