Android 带回调的启动Activity 推荐使用registerForActivityResult

今天无意间发现平常使用的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、startActivityForResult

   val register = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if(it.resultCode == RESULT_OK){
                val keyWords = it.data?.getStringExtra(SearchCompanyActivity.KEY_CODE) ?: ""
                if (keyWords.isNotEmpty()) {
                    mViewModel.keyWords = keyWords
                    mVb.tvSearch.text = mViewModel.keyWords
                    mVb.ivCleanKeywords.visibility = View.VISIBLE
                    mVb.refreshLayout.autoRefresh()
                }
            }
        }

//启动Activity
   register.launch(Intent(this@AdvanceOnWorkActivity,SearchCompanyActivity::class.java))

2、单个权限申请

     //单个权限申请
        val launcherPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()){
            if(it) {
                //同意
            }else{
                //拒绝
            }
        }

launcherPermission.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)

3、多个权限申请

  //多个权限申请单个权限
        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))

4、图片选择(单张、多张)

   //选择一张图片
        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/*

这里的不仅能选择图片,还能选择视频、文档等,只需要配置下launch中的文件类型就可以了

注意的是文件选择都是以uri的形式返回,在使用的时候需要转为实际的存储路径

四、总结

系统实现类中还有,调用相机拍照、录制视频、选择联系人等大家可以试一下,总体感觉非常方便,尤其是权限申请个人感觉很实用。另外的图片选择因为各个Android系统包括手机的差异在UI上会有所不同,这个看你怎么选择了

参考:使用registerForActivityResult接受从activity返回的数据 - 灵剑山真人 - 博客园

        ActivityResultContracts.OpenMultipleDocuments  |  Android Developers

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值