今天无意间发现平常使用的startActivityForResult(intent,code)过时了,然后点进看:
/**
* {@inheritDoc}
*
* @deprecated use
* {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
* passing in a {@link StartActivityForResult} object for the {@link ActivityResultContract}.
*/
@Override
@Deprecated
public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
int requestCode, @Nullable Bundle options) {
super.startActivityForResult(intent, requestCode, options);
}
其中有一个registerForActivityResult的方法介绍链接,然后Google开发文档了解了下,发现了这个替代的方法功能很全,使用起来相对来说也很简单(除基本的使用方法外(⊙o⊙)…)
一、添加引用
implementation 'androidx.appcompat:appcompat:1.3.1'
目前我用的这个版本是1.3.1,1.3.0以下版本是没有这个替代方法的,注意你的appcompat版本
二、基本使用
//常规带回调启动Activity
val launcher = registerForActivityResult(object : ActivityResultContract<String, String>() {
override fun createIntent(context: Context, input: String?): Intent {
//创建启动页面所需的Intent对象,穿入需要传递的参数
return Intent(this@MainActivity, SecondActivity::class.java).apply {
putExtra("key", input)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): String {
//页面回传的数据解析,相当于原onActivityResult方法
val data = intent?.getStringExtra("result") ?: ""
return if (resultCode == RESULT_OK) data else ""
}
}) {
//获取parseResult解析的数据
Log.e(TAG, "data:$it")
}
调用registerForActivity(ActivityResultContract<I,O>,ActivityResultCallBack<O>):
ActivityResultContract:内部有两个抽象方法,一个createItent,创建需要启动的页面Intent对象,同时也可传参,另外的parseResult,数据的解析在这么处理,并返回;
ActivityResultCallBack:内部只有一个抽象方法onActivityResult(),上面的写法使用的lambda简化写法,直接移到方法括号外部,这里面的回调方法是接收上面parseResult解析的数据
注意:registerForActivity返回一个launcher对象,创建的时候得在Activity中的onCreate方法中创建,使用的时候这样用
launcher.launch("传递给第二个页面的数据:你好吗?")
从上面可知,我们主要在创建contract的时候比较麻烦,不过官方给了如下实现类,包含了开发中常见业务:比如选择图片、视频、联系人、权限申请等
StartActivityForResult: 通用的Contract,不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定。
RequestMultiplePermissions: 用于请求一组权限
RequestPermission: 用于请求单个权限
TakePicturePreview: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片
TakePicture: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功。
TakeVideo: 调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图。
PickContact: 从通讯录APP获取联系人
GetContent: 提示用选择一条内容,返回一个通过ContentResolver#openInputStream(Uri)访问原生数据的Uri地址(content://形式) 。默认情况下,它增加了Intent#CATEGORY_OPENABLE, 返回可以表示流的内容。
CreateDocument: 提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri。
OpenMultipleDocuments: 提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式。
OpenDocumentTree: 提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。
三、自带实现类举例
1、单个权限申请
//单个权限申请
val launcherPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()){
if(it) {
//同意
}else{
//拒绝
}
}
launcherPermission.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
2、多个权限申请
//多个权限申请单个权限
val launcherPermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){
//逐个判断权限是否有
if(it[Manifest.permission.CAMERA]!!){
//同意
}else{
//拒绝
}
if(it[Manifest.permission.WRITE_EXTERNAL_STORAGE]!!){
//同意
}else{
//拒绝
}
}
launcherPermissions.launch(arrayOf(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE))
3、图片选择(单张、多张)
//选择一张图片
val launcherImg = registerForActivityResult( ActivityResultContracts.OpenDocument()){
Log.e(TAG,"path:${it.path}")
}
launcherImg.launch(arrayOf("image/*"))
//选择多张图片
val launcherImgs = registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()){
it.forEach { uri->
Log.e(TAG,uri.toString())
}
}
launcherImgs.launch(arrayOf("image/*"))// 例如视频:video/*
这里的不仅能选择图片,还能视频、text等,只需要配置下launch中的文件类型就可以了
注意的是文件选择都是以uri的形式返回,在使用的时候需要转为实际的存储路径
四、总结
系统实现类中还有,调用相机拍照、录制视频、选择联系人等大家可以试一下,总体感觉非常方便,尤其是权限申请个人感觉很实用。另外的图片选择因为各个Android系统包括手机的差异在UI上会有所不同,这个看你怎么选择了
参考:https://www.cnblogs.com/--here--gold--you--want/p/14841024.html
????????https://developer.android.google.cn/reference/androidx/activity/result/contract/ActivityResultContracts.OpenMultipleDocuments?hl=en
|