• Jetpack架构组件学习(3)——Activity Results API使用


    本文为作者原创,转载请注明出处,谢谢配合
    作者:stars-one
    链接:https://www.cnblogs.com/stars-one/p/16364187.html

    本篇大约有4537个字,阅读预计需要5.67分钟


    原文地址:Jetpack架构组件学习(3)——Activity Results API使用 - Stars-One的杂货小窝

    技术与时俱进,页面跳转传值一直使用的是startActivityForResult方法,如今有了新的API实现方式,学习并稍微总结下 😄

    startActivityForResult复习

    MainActivity代码:

    Main2Activity代码:

    效果:

    上面的代码应该是比较基础的代码,这里我就不再赘述了

    主要说些缺点

    所有逻辑都在onActivityResult()方法里进行判断,根据requestCoderesultCode进行判断

    如果单个还好说,但是如果有多个的,就会看见onActivityResult()里一堆的if逻辑,阅读起来就十分繁琐,且维护困难

    谷歌官方也是考虑到了这个,于是便是在新版本推出了个Activity Results API去替代了上面所述的方式,下面就介绍下如何使用

    简单使用

    1.引入依赖

    首先,需要我们引入依赖:

    implementation 'androidx.appcompat:appcompat:1.3.1'
    

    PS: 请使用1.3.1以上版本,低版本没有这个枚举类ActivityResultContracts

    我们先以上面的例子,使用Activity Results API

    Main2Acitivity代码不用动,我们只需要调整MainActivity文件里代码,如下所示:

    2.创建契约

    val contract = ActivityResultContracts.StartActivityForResult()
    

    contract变量的对象类名为ActivityResultContract

    ActivityResultContracts相当于一个枚举类,是谷歌官方贴心封装的,里面提供了一些常用的ActivityResultContract类对象供我们使用

    像拍照,申请权限的等操作,从代码提示就可以看到了,如下图所示:

    这里我们选用StartActivityForResult(),字面意思应该很好理解,就是应用在就是页面跳转并返回数据的情景

    PS:根据我们选用的ActivityResultContracts,会影响第4步中的传参类型

    下面补充下对应的选择说明:

    • StartActivityForResult: 通用的Contract,不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定。
    • CreateDocument: 提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri。
    • GetContent: 提示用选择一条内容,返回一个通过ContentResolver#openInputStream(Uri)访问原生数据的Uri地址(content://形式) 。默认情况下,它增加了 Intent#CATEGORY_OPENABLE, 返回可以表示流的内容。
    • GetMultipleContents:获取多条内容
    • OpenDocument: 提示用户选择指定类型文件(输入参数为mimeType),返回用户所选文件Uri
    • OpenDocumentTree: 提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。
    • OpenMultipleDocuments: 提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式。
    • PickContact: 从通讯录APP获取联系人
    • RequestMultiplePermissions:用于请求一组权限
    • RequestPermission: 用于请求单个权限
    • TakePicturePreview: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片
    • TakePicture: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功。
    • TakeVideo: 调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图。

    具体参数和说明可以使用的时候查看文档哦~

    实际上,如果上面所列还不能满足我们的需求,那么我们也可以自定义契约操作,在文章下面再进行补充说明,这里就先不进行扩展了

    3.建立契约(注册Contact)

    //注册ActivityResultContract
    val myLauncher = registerForActivityResult(contract){
        if (it.resultCode==2) {
            val data = it.data
            if (data != null) {
                val resultData = data.getStringExtra("mydata")
                Toast.makeText(this, resultData, Toast.LENGTH_SHORT).show()
            }
        }
    }
    

    使用Activity类中registerForActivityResult()方法,进行契约的注册,实际上就是相当于注册了一个监听,之后从Main2Activity页面返回MainActivity页面,会回调这个里面的方法

    注意: registerForActivityResult方法需要在Activity的生命周期的onStart()之前前进行调用!!

    4.发起页面跳转

    val intent = Intent(this, Main2Activity::class.java)
    myLauncher.launch(intent)
    

    调用myLauncher对象的launch()方法,将intent对象传递即可实现页面跳转的操作

    PS: 这里还是在按钮的点击事件里,方便阅读就省略了

    之后从Main2Activity页面返回之后,会回调第二步中的操作,效果与上面的动图演示一致,这里就不再重新贴个图了

    自定义ActivityResultContract

    ActivityResultContract实际上还包含两个泛型,完整应该是这样ActivityResultContract<I,O>

    • I为input的意思,意为输入参数类型
    • O为output的意思,意为输出参数类型

    ActivityResultContract<I,O>是个抽象类,我们想要实现自定义,那么就直接继承它

    class MyContract: ActivityResultContract<String, String>() {
    
        override fun createIntent(context: Context, input: String?): Intent {
            //这里input的类型,就是上文说到的I
        }
    
        override fun parseResult(resultCode: Int, intent: Intent?): String {
            //这里方法返回的结果类型,就是上文说到的O
            
        }
    
    }
    

    继承发现,需要我们实现两个方法,createIntent()parseResult()

    一眼过去其实很好理解,createIntent()就是创建一个intent对象,调用launch()方法的时候(上面使用的第4步操作),里面就会根据此intent进行页面的跳转操作

    parseResult()方法,则是建立契约那步,里面回调的数据类型

    我们以上面的例子,发现我们还得声明一个Intent对象传递,以及回传的时候还得通过intent对象去获取数据,有些繁琐,有些代码可以封装成通用的

    照着这个想法,我们可以实现一个自定义ActivityResultContract,传递页面参数即可拿到Main2Activity返回的数据,代码如下所示:

    class MyContract: ActivityResultContract<KClass<out Activity>, String>() {
        
        override fun parseResult(resultCode: Int, intent: Intent?): String? {
            if (resultCode == 2 && intent!=null) {
                return intent.getStringExtra("mydata")
            }
            return null
        }
    
        override fun createIntent(context: Context, input: KClass<out Activity>?): Intent {
            val intent = Intent(context,input?.java)
            return intent
        }
    
    }
    

    使用:

    //1.创建契约
    val contract = MyContract()
    
    //2.注册ActivityResultContract
    val myLauncher = registerForActivityResult(contract){
        Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
    }
    
    btnGo.setOnClickListener {
        //2.发起页面跳转
        myLauncher.launch(Main2Activity::class)
    }
    

    当然,这里还可以优化,如我们让MyContract多个构造函数,这样取值的key也可以通过此进行定义

    class MyContract(val key: String) : ActivityResultContract<KClass<out Activity>, String>() {
    
        override fun parseResult(resultCode: Int, intent: Intent?): String? {
            if (resultCode == 2 && intent != null) {
                return intent.getStringExtra(key)
            }
            return null
        }
    
        override fun createIntent(context: Context, input: KClass<out Activity>?): Intent {
            val intent = Intent(context, input?.java)
            return intent
        }
    
    }
    

    使用:

    //创建契约里传参即可
    val contract = MyContract("mydata")
    

    参考

  • 相关阅读:
    LeetCode之二叉树
    设置session失效时间
    代码随想录 贪心算法-简单题目
    Neo4j 创建关系
    微服务项目:尚融宝(4)(上手复习mybatisplus)
    C++自己封装的简易的较安全的智能指针
    深入学习git
    卤味江湖混战:紫燕、德州扒鸡IPO,卤味下半场跳出“鸭圈“
    不得不会的MySQL数据库知识点(五)
    A brief Introduction to Continue Learning / Life long Learning
  • 原文地址:https://www.cnblogs.com/stars-one/p/16364187.html