在 Android 中,我们如果想在 Activity 之间双向传递数据,需要使用 startActivityForResult 启动,然后在 onActivityResult 中处理返回,另外申请权限也是类似的步骤。
但是这样的处理方式会让我们的代码变得非常复杂,并且也无法保证在 Activity 发送或接收数据时参数的类型安全。
ActivityResult 是 Jetpack 提供的一个功能,可以简化 Activity 直接的数据传递 (包括权限申请)。它通过提供类型安全的 contract (协定) 来简化处理来自 Activity 的数据。这些协定为一些常见操作 (比如: 拍照或请求权限) 定义了预期的输入和输出类型,除此之外您还能够自定义协定来满足不同场景的需求。
ActivityResult API 提供了一些组件用于注册 Activity 的处理结果、发起请求以及在系统返回结果后立即进行相应处理。您也可以在启动 Activity 的地方使用一个独立的类接收返回结果,这样依然能够保证类型安全。

一、ActivityResult 使用

使用 ActivityResult 先添加依赖:

dependencies {// 在 https://developer.android.google.cn/jetpack/androidx/releases/activity 获得最新版本号def activity_version = "1.2.0"// 在 https://developer.android.google.cn/jetpack/androidx/releases/fragment 获得最新版本号def fragment_version = "1.3.0"implementation "androidx.activity:activity:$activity_version"implementation "androidx.fragment:fragment:$fragment_version”
}

然后先看看最简单的使用方式,比如打开系统文件管理器选择一个图片,代码如下:

val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->// 处理返回的 Uri
}getContent.launch("image/*") //过滤图片

这里涉及几个重要的类和函数:

(1) registerForActivityResult: 是 ComponentActivity 的一个函数,注意这里的 ComponentActivity 是 androidx.activity.ComponentActivity 而不是 androidx.core.app.ComponentActivity,androidx.core 中的对应类 (截止 1.3.0) 还不支持这项功能。

public final <I, O> ActivityResultLauncher<I> registerForActivityResult(@NonNull ActivityResultContract<I, O> contract,@NonNull ActivityResultCallback<O> callback)

可以看到这个函数接收两个参数,分别是 ActivityResultContract 和回调 ActivityResultCallback,ActivityResultContract 是封装启动所需要的各项参数 (组成 Intent,后面会细说)。函数返回 ActivityResultLauncher,可以看到后面通过他的 launch 函数就可以启动 activity。

(2) GetContent: ActivityResultContracts.GetContent 类是一个继承 ActivityResultContract 的具体实现类,封装了调用系统文件管理器的功能。Jetpack 提供了一些常用的 ActivityResultContract,比如选取图片,拍照等等,如果我们需要拉起自己的 Activity,就需要自定义一个 ActivityResultContract。

(3) launch: ActivityResultLauncher 的函数,启动 activity,代替了之前的 startActivity。

二、在 Jetpack 提供的已封装好的 ActivityResultContract 有 (都是 ActivityResultContracts 的子类):

(1) StartActivityForResult:

最简单的,相当于传统方式的 startActivityForResult,只不过将 onActivityResult 的几个参数封装成一个 ActivityResult。

(2) StartIntentSenderForResult:

相当于 Activity.startIntentSender(IntentSender, Intent, int, int, int),与 PendingIntent 配合使用。

(3) RequestMultiplePermissions:

用于批量申请权限。以 Map 形式返回每个权限的情况。

(4) RequestPermission

申请单个权限,通过这两个来申请权限就可以很方便的进行后续处理。

(5) TakePicturePreview

拉起拍照预览,直接返回 bitmap 数据。(跟传统方式一样,这个 bitmap 只是一个图片预览,因为 intent 中不能传输过大的数据) 。
注意虽然输入是 Void,但是执行 ActivityResultLauncher 的 lanch 函数是还需要传入一个 null 才行。

(6) TakePicture

拉起拍照,输入图片要保存的位置 uri

(7) TakeVideo

录制视频,输入视频要保存的位置 uri,返回视频的缩略图

(8) PickContact

选取联系人

(9) GetContent

获取单个文件,输入过滤类型,返回文件 uri

(10) GetMultipleContents

文件多选,同上

(11) OpenDocument

打开单个文档 (拉起的是系统文档管理器)
对应 Intent.ACTION_OPEN_DOCUMENT,输入的是类型过滤 (如 image/*),输出 uri

(12) OpenMultipleDocuments

打开多个文档,与上面类似

(13) OpenDocumentTree

打开文档 tree,对应 Intent.ACTION_OPEN_DOCUMENT_TREE

(14) CreateDocument

新建一个文档,对应 Intent.ACTION_CREATE_DOCUMENT

可以看到 Android 已经将常用的功能都封装了,基本可以满足我们的开发使用。

三、使用TakePicture调起拍照实例

代码:MainActivity.kt

class MainActivity : AppCompatActivity() {private lateinit var mImageView: ImageViewprivate lateinit var mImageView1: ImageViewprivate var mUri: Uri? = nullprivate var mTextView: TextView? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)mImageView = findViewById(R.id.image)mImageView1 = findViewById(R.id.image1)mTextView = findViewById(R.id.tx)Glide.with(this).load("/storage/emulated/0/Android/data/com.example.myapplication/cache.jpg").into(mImageView1)mUri = FileProvider.getUriForFile(this, applicationContext.packageName + ".fileprovider",File(externalCacheDir!!.absolutePath + ".jpg"))findViewById<Button>(R.id.button).setOnClickListener {mTakePicture.launch(mUri)}}private val mTakePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) {if (it) {try {val bmp = MediaStore.Images.Media.getBitmap(contentResolver,Uri.fromFile(File(mUri?.path.toString().substring(5))))mImageView.setImageBitmap(bmp)} catch (e: IOException) {e.printStackTrace()}}}
}

代码说明:
1、代码中有一个mImageView和一个mImageView1,在mTakePicture代码块中,如果直接使用Glide.with(this).load方式加载图片至mImageView,没图片时会成功,有图片后,会出现图片不更新,不是刚所拍照片,是因为直接使用uri会有缓存的原因。故使用Bitmap方式去加载图片。
2、之所以mUri?.path需要substring(5),因为mUri?.path的路径为(/root/storage/emulated/0/Android/data/com.example.myapplication/cache.jpg),多了一个/root,导致读取不到照片,所以需要将其处理一下。
3、实现此实例还需要申请读写权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

4、需要在AndroidManifest.xml中加入:

       <providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.example.myapplication.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider>

Android 使用 ActivityResult 处理 Activity 之间的数据通信及调起拍照实例相关推荐

  1. Jetpack:使用 ActivityResult 处理 Activity 之间的数据通信

    目录 前言 ActivityResult使用 ActivityResultContract 原理 总结 前言 本文先介绍ActivityResult的基本使用,最后会通过源码来探讨背后的原理. 在An ...

  2. Android中BroadCast与Activity之间的通信

    在看本文之前,假设你对于Android的广播机制不是非常了解.建议先行阅读我转载的一篇博文:图解 Android 广播机制. 因为本案例比較简单,故直接在此贴出代码,不做过多的阐述. 先上效果截图: ...

  3. Android(Fragment和Activity之间通信)

    Fragment的使用可以让我们的应用更灵活的适配各种型号的安卓设备,但是对于Fragment和Activity之间的通信,很多朋友应该比较陌生,下面我们就通过一个实例来看一看如何实现. 一.Acti ...

  4. (转载)Android进阶2之Activity之间数据交流(onActivityResult的用法)

    转载自  http://www.blogjava.net/mixer-a/archive/2012/03/23/375014.html 主要功能: 在一个主界面(主Activity)上能连接往许多不同 ...

  5. Android 程序,实现Activity之间的跳转

    大概效果:在Activity1中有一个Button,当点击Button时,跳转到Activity2.跳转时,由Activity1向Activity2传递字符串,使Activity2中原本为空的Text ...

  6. Android笔记:Fragment与Activity之间的交互,onAttach,退出最后一个 fragment

    一.交互代码笔记: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28     private Log ...

  7. ​Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]

    Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable] 在Android中的不同Activity之间传递对象,我们可以考虑采用Bun ...

  8. java 传递intent_Android中使用Intent在Activity之间传递对象(使用Serializable或者Parcelable)的方法...

    Android中的不同Activity之间传递对象,我们可以考虑采用Bundle.putSerializable(Key,Object);也可以考虑采用Bundle.putParcelable(Key ...

  9. 从Android中Activity之间的通信说开来

    引言 最近两个星期在研究android的应用开发,学习了android应用开发的基础知识,基本控件,基本布局,基本动画效果,数据存储,http访问internet等等基础知识. android中有一个 ...

最新文章

  1. Android Activity从右边到左边跳转(overridePendingTransition)
  2. C# 3.0 —— 扩展方法
  3. 皮一皮:同一样物件,不一样的时间...
  4. [Swift]LeetCode793. 阶乘函数后K个零 | Preimage Size of Factorial Zeroes Function
  5. fcn从头开始_如何使用Go从头开始构建区块链
  6. dijikstra 旅行商问题_第27期:基于旅行商问题(TSP)的配送网络优化—R实现
  7. python如何调用阿里云接口_Python调用阿里云API接口实现自定义功能【二】——DescribeInstance窗口操作...
  8. IOS开发学习笔记(一)——ObjectC语言快速入门
  9. plsql导出数据字典
  10. java创建mysql视图_Mysql视图的创建及使用
  11. HTML Typo.css 中文网页重设与排版
  12. 火狐老是跳出提示“Firefox正在安装组件,以便播放此页面上......”
  13. 有一个已排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中
  14. 东莞潇洒老师:分享PROE产品设计塑胶产品结构基本设计
  15. python开源oa系统_最全总结 | 聊聊 Python 办公自动化之 Word(下)
  16. 【GDOI2016】疯狂动物城 题解
  17. php备忘录,备忘录模式及其php实现
  18. win服务器系统路由器,Windows server 2012 之路由功能
  19. 广义item2vec的典型例子----双塔模型
  20. 【毕业设计】深度学习图像语义分割算法研究与实现 - python 机器视觉

热门文章

  1. HTTPS通信的C++实现
  2. [日常] 算法-旋转字符串-暴力移位法
  3. 深入源码 UITableView 复用技术原理分析
  4. 百度地图api location 211 sn校验失败
  5. QT STUDY 模型-视图-控制器
  6. 创建ACFS集群文件系统(命令方式)
  7. Android根据baidu Android定位SDK实现定位
  8. faststone 注册码
  9. 信息系统项目管理系列之一:绪论
  10. ip地址管理与子网的划分二