ActivityResultLauncher使用 - SheTieJun/BaseKit GitHub Wiki
当前基于androidx.activity
的1.4.0
版本
1. 替代startActivityForResult
2. 注册必须在Activity#onStart()? 不,我们完全可以在用的时候才创建并使用
首先我们需要了解有哪些自带的ActivityResultContract
-
StartActivityForResult
使用Intent在activity(fragment)间通信,返回ActivityResult -
StartIntentSenderForResult
使用IntentSenderRequest. builder构造,可以返回带有activity的ActivityResult -
RequestMultiplePermissions
获取多个动态权限,返回Map<String,boolean>数组 -
RequestPermission
获取单个动态权限,成功后返回true -
TakePicturePreview
调用相机,拍照后返回bitmap图片信息 -
TakePicture
调用相机,拍照后将图片保存到开发者指定的Uri,返回true -
TakeVideo
拍摄视频,将拍摄内容保存到开发者指定的Uri,返回缩略图 -
CaptureVideo
拍摄视频,将内容保存到开发者指定的Uri后,返回true -
PickContact
弹出手机联系人列表,用户选中其中一个后,返回Uri -
GetContent
访问原始数据,返回Uri,例如相册中的单个图片 -
GetMultipleContents
功能如上,返回Uri数组,例如相册中的多个图片 -
OpenDocument
访问文件数据,打开文件夹,返回单个文件的Uri -
OpenMultipleDocuments
功能如上,返回多个文件的Uri OpenDocumentTree
-
CreateDocument
创建文件
当然也可以自己定义,不过上面已经基本满足我们的需求了。
eg:
class UserActivityResultContract : ActivityResultContract<String, UserInfo?>() {
override fun createIntent(context: Context, input: String): Intent {
val intent = Intent(context, UserInfoActivity::class.java)
intent.putExtra("url", input)
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?): UserInfo? {
if (resultCode == Activity.RESULT_OK) {
if (intent?.hasExtra("userInfo") == true) {
if (intent.getSerializableExtra("userInfo") != null) {
return intent.getSerializableExtra("userInfo") as UserInfo
}
}
}
return null
}
}
大家一般是在Fragment
或者Activity
中使用,需要在onCreate中使用registerForActivityResult
注册一下得到ActivityResultLauncher
,
需要注意的是,通过源码androidx.activity.ComponentActivity#registerForActivityResult
:
if (lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
throw new IllegalStateException("LifecycleOwner " + lifecycleOwner + " is "
+ "attempting to register while current state is "
+ lifecycle.getCurrentState() + ". LifecycleOwners must call register before "
+ "they are STARTED.");
}
在Activity
必须在onStart
及之前执行。
androidx.fragment.app.Fragment#registerForActivityResult
if (mState > CREATED) {
throw new IllegalStateException("Fragment " + this + " is attempting to "
+ "registerForActivityResult after being created. Fragments must call "
+ "registerForActivityResult() before they are created (i.e. initialization, "
+ "onAttach(), or onCreate()).");
}
在fragment
必须在onCreate
及以前执行。
案例:
直接在在Fragment
或者Activity
中创建ActivityResultLauncher
private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
//结果
}
然后在要调用的地方
permissionLauncher.launch(arrayOf(
Manifest.permission.WRITE_CALENDAR,
Manifest.permission.READ_CALENDAR
))
总结:
使用
registerForActivityResult
注册得到ActivityResultLauncher
,在Activity
必须在onStart
及之前执行,在fragment
必须在onCreate
及以前执行。
答案:当然不是
通过源码我可以知道,实际上注册获取ActivityResultLauncher
是通过ActivityResultRegistry
注册,通过查看源码然后我发现还有一个注册方法是不需要LifecycleOwner
。
这样我们就可以在任意一个地方只要有Activity的上下文(context)就可以注册获取ActivityResultLauncher
。
首先通过context
(需要注意这里的context,要判断是否ComponentActivity
)
androidx.activity.ComponentActivity#getActivityResultRegistry
获取ActivityResultRegistry
然后通过下面的方法进行注册:
于是添加了下面的扩展方法,进行注册获取ActivityResultLauncher
:
Activity:
fun <I, O> ComponentActivity.register(
@NonNull key: String,
@NonNull contract: ActivityResultContract<I, O>,
@NonNull callback: ActivityResultCallback<O>
): ActivityResultLauncher<I> {
return activityResultRegistry.register(key, contract, callback).also {
lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Event) {
if (event == Event.ON_DESTROY) {
it.unregister()
}
}
})
}
}
fragment:
fun <I, O> Fragment.register(
@NonNull key: String,
@NonNull contract: ActivityResultContract<I, O>,
@NonNull callback: ActivityResultCallback<O>
): ActivityResultLauncher<I> {
return requireActivity().activityResultRegistry.register(key, contract, callback).also {
lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Event) {
if (event == Event.ON_DESTROY){
it.unregister()
}
}
})
}
}
使用案例:
fun ComponentActivity.startActivityResult2(
@NonNull key: String = "startActivityResult" + mNextLocalRequestCode.getAndIncrement(),
@NonNull intent: Intent,
@NonNull callback: ActivityResultCallback<ActivityResult>
) {
return register(key,ActivityResultContracts.StartActivityForResult(), callback)
.also {
lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Event) {
if (event == Event.ON_DESTROY) {
it.unregister()
}
}
})
}.launch(intent)
}
在ComponentActivity
需要的地方进行直接调用就可以了
startActivityResult2(intent = Intent(this,TestActivity::class.java)){
it.resultCode.toString().logI()
}
-
使用
registerForActivityResult
注册得到ActivityResultLauncher
,在Activity
必须在onStart
及之前执行,在fragment
必须在onCreate
及以前执行。 -
ActivityResultLauncher
的注册实际上是通过ActivityResultRegistry
注册获取的 -
ActivityResultRegistry
有2个注册方法,其中一个并不需要LifecycleOwner
,所以通过这个新的注册方法我们可以不遵守:在Activity
必须在onStart
及之前执行,在fragment
必须在onCreate
及以前执行。 -
Fragment
在使用register的是时候需要注意Activity是不是为空,否则会异常