写点什么

Android 11 适配指南之系统相机拍照、打开相册,腾讯 & 字节 & 爱奇艺 & 网易 & 华为实习面试汇总

作者:嘟嘟侠客
  • 2021 年 11 月 27 日
  • 本文字数:2447 字

    阅读完需:约 8 分钟

  • Android 6 权限适配

  • Android 7 文件适配

  • Android 10/11 存储适配


ok,接下来以一个更换头像的小例子来讲解一下。


示例


=============================================================



点击头像,然后弹窗,给出不同的选项,执行不同的操作。


mBinding.llImg.setOnClickListener {


TakeImageDialog {


when (it) {


TakeImageDialog.ALBUM -> {


openAlbum()


}


TakeImageDialog.CAMERA -> {


checkPermission()


}


}


}.show(supportFragmentManager, "TakeImageDialog")


}


定义后面会用到的一些参数变量


//相机拍照保存的位置


private lateinit var photoUri: Uri


companion object {


private const val REQUEST_CODE_PERMISSIONS = 1000 //权限


private const val REQUEST_CODE_ALBUM = 1001 //相册


private const val REQUEST_CODE_CAMERA = 1002 //相机


}


打开相册


===============================================================

选择图片

private fun openAlbum() {


val intent = Intent()


intent.type = "image/*"


intent.action = "android.intent.action.GET_CONTENT"


intent.addCategory("android.intent.category.OPENABLE")


startActivityForResult(intent, REQUEST_CODE_ALBUM)


}


固定写法,大差不差。


既然是startActivityForResult启动方式,来看看onActivityResult回调

回调

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {


super.onActivityResult(requestCode, resultCode, data)


if (resultCode == RESULT_OK) {


when (requestCode) {


REQUE


《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享


ST_CODE_ALBUM -> {


doCrop(data?.data!!)


}


...


}


}


}


requestCodeREQUEST_CODE_ALBUM的情况下:


doCrop(data?.data!!)


data?.data!!即是选择图片返回的Uri,可以直接使用,这里进行了下一步操作,剪裁

剪裁

private fun doCrop(sourceUri: Uri) {


Intrinsics.checkParameterIsNotNull(sourceUri, "资源为空")


UCrop.of(sourceUri, getDestinationUri())//当前资源,保存目标位置


.withAspectRatio(1f, 1f)//宽高比


.withMaxResultSize(500, 500)//宽高


.start(this)


}


为了方便,这里使用了一个三方库UCrop,使用简单方便。


getDestinationUri()是当前资源裁剪后保存的目标位置


private fun getDestinationUri(): Uri {


val fileName = String.format("fr_crop_%s.jpg", System.currentTimeMillis())


val cropFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName)


return Uri.fromFile(cropFile)


}


UCrop的回调同样也在onActivityResult


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {


super.onActivityResult(requestCode, resultCode, data)


if (resultCode == RESULT_OK) {


when (requestCode) {


REQUEST_CODE_ALBUM -> {


doCrop(data?.data!!)


}


UCrop.REQUEST_CROP -> {


val resultUri: Uri = UCrop.getOutput(data!!)!!


val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(resultUri))


// todo


}


UCrop.RESULT_ERROR -> {


val error: Throwable = UCrop.getError(data!!)!!


ToastUtil.show("图片剪裁失败" + error.message)


}


}


}


}


UCrop.getOutput(data!!)!!,即是返回的 Uri,可以直接操作,也可以转成bitmap


ok,到这里打开相册就介绍完了。


接下来看重点,打开相机。


author:yechaoa


打开相机


===============================================================


打开相机的流程就要稍微复杂一点了。

权限

第一步不是打开,而是先检查是否有相机权限,这个在某些手机上是必须的,比如华为。


  • 配置文件添加:


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


  • 代码:


private fun checkPermission() {


if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {


openCamera()


} else {


ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_CODE_PERMISSIONS)


}


}


  • 回调:


override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {


super.onRequestPermissionsResult(requestCode, permissions, grantResults)


if (requestCode == REQUEST_CODE_PERMISSIONS) {


if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {


openCamera()


} else {


ToastUtil.show("拒绝会导致无法使用相机")


}


}


}


openCamera方法就是打开相机了。

打开前适配

private fun openCamera() {


val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)


photoUri = getDestinationUri()


photoUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {


//适配 Android 7.0 文件权限,通过 FileProvider 创建一个 content 类型的 Uri


FileProvider.getUriForFile(this, "$packageName.fileProvider", File(photoUri.path!!))


} else {


getDestinationUri()


}


//android11 以后强制分区存储,外部资源无法访问,所以添加一个输出保存位置,然后取值操作


intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)


startActivityForResult(intent, REQUEST_CODE_CAMERA)


}


  • 适配一:


FileProvider.getUriForFile(this, "$packageName.fileProvider", File(photoUri.path!!))


7.0 以上,使用fileProvider的方式共享文件。

资源分享




网上学习 Android 的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。


2020 年虽然路途坎坷,都在说 Android 要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家 2021 年万事大吉。


本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

用户头像

嘟嘟侠客

关注

还未添加个人签名 2021.03.19 加入

还未添加个人简介

评论

发布
暂无评论
Android 11适配指南之系统相机拍照、打开相册,腾讯&字节&爱奇艺&网易&华为实习面试汇总