Android保存照片到相册
Android保存照片到相册
前言
随着Android系统的不断升级 从最初的第一个版本 更新到现在 Android 11.0 Beta
都出炉了 Android 11.0
也即将面试 系统的不断更新完善 用户体验也是蹭蹭蹭的 隐私安全方面也是越来越给力了 这对用户当然是一级棒 对于开发者 简直无力吐槽 因为碎片化问题 加上版本更新迭代 废弃淘汰一堆 API
脑瓜子疼。
正文
这几天刚刚需要保存视频到相册 发现 我去 以前的方法好像不太给力了,磨了 我好久。。因为我手机是Android 10
版本 从用户隐私加强了 最大的变化就是 存储权限
Android 10
在外部存储设备中为每个应用提供了一个“隔离存储沙盒”(例如 /sdcard
)。任何其他应用都无法直接访问您应用的沙盒文件。由于文件是您应用的私有文件,因此您不再需要任何权限即可在外部存储设备中访问和保存自己的文件。此变更可让您更轻松地保证用户文件的隐私性,并有助于减少应用所需的权限数量。
所以就是说我们不能直接访问 根目录 了? 其实 在Android 10
上还不是完全杜绝你使用的 你还是可以兼容低版本 那怎么做呢
<application
...
android:requestLegacyExternalStorage="true">
</application>
只需要在 你的AndroidManifest.xml
文件中 加入这行代码 意思就是申请旧版本的外部存储 那么你还是可与愉快玩耍的
可是旧版本的外部存储权限都已经废弃了 这样做是可以解决当前的问题 但是在Android 11
上 讲严格执行沙盒存储方式 也就是说 这样的代码在Android 11
上已经无法兼容了 并且的 10 的系统兼容也不够
撸码环节
那么开始撸代码把
/**
*保存bitmap
*/
fun saveBitmap2Gallery(context: Context, bitmap: Bitmap): Boolean {
val name=System.currentTimeMillis().toString()
val photoPath=Environment.DIRECTORY_DCIM + "/Camera"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME,name )
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.MediaColumns.RELATIVE_PATH, photoPath)//保存路径
put(MediaStore.MediaColumns.IS_PENDING, true)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//返回出一个URI
val insert = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
) ?: return false //为空的话 直接失败返回了
//这个打开了输出流 直接保存图片就好了
context.contentResolver.openOutputStream(insert).use {
it ?: return false
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
}
return true
} else {
MediaStore.Images.Media.insertImage(context.contentResolver, bitmap, "title", "desc")
return true
}
}
就上面的代码 可以直接保存了 如果不挑剔 应该是可以使用的了 但是发现一个问题 除了Android 10
以上的 用 MediaStore
提示是废弃的 蒙蔽 为什么废弃呢 我们进入文档看看
inserting of images should be performed using {@link MediaColumns#IS_PENDING}, which offers richer control over lifecycle.
一看文档一脸懵逼 没看懂什么 各种查阅资料 百度一堆都是废弃的API
。。。Android
这么难吗 保存个图片 都没有一个兼容的 完美的解决方案 或者 API
经过漫长的查询 种算看到眉目了 改良后的代码是这样的
fun saveBitmap2Gallery2(context: Context, bitmap: Bitmap): Boolean {
val name = System.currentTimeMillis().toString()
val photoPath = Environment.DIRECTORY_DCIM + "/Camera"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, photoPath)//保存路径
put(MediaStore.MediaColumns.IS_PENDING, true)
}
}
val insert = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
) ?: return false //为空的话 直接失败返回了
//这个打开了输出流 直接保存图片就好了
context.contentResolver.openOutputStream(insert).use {
it ?: return false
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.MediaColumns.IS_PENDING, false)
}
return true
}
是简单了好多 发现 在Android 10
一下 只需要屏蔽 RELATIVE_PATH
和 IS_PENDING
就可以了
但是发现一个问题 在Android 默认是保持在 /sdCard/Pictures/
虽说也存放图片的地方 但是不是 /sdCard/DCIM/Camera
在小米 OV
等手机上 不能直接显示在照片里 而是在相册 中的 Pictures里 或者在全部照片也可以查到 这个问题我还是不知道怎么解决 因为 在使用 ContentValues
时 10.0以下的系统是不能设置路径的 那怎么办 可能还是的用废弃的 API
了 这里方法提供了 2种 自行选择最适合自己的 如果知道怎么保存到DCIM
欢迎评论区解答下
最后需要注意的是 在Android 10
中 保存到相册是不需要存储权限的 在6 - 9
的版本中 需要存储权限
整合放出代码
object PhotoUtils {
fun saveBitmap2Gallery(context: Context, bitmap: Bitmap): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//返回出一个URI
val insert = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
/*
这里如果不写的话 默认是保存在 /sdCard/DCIM/Pictures
*/
ContentValues()//这里可以啥也不设置 保存图片默认就好了
) ?: return false //为空的话 直接失败返回了
//这个打开了输出流 直接保存图片就好了
context.contentResolver.openOutputStream(insert).use {
it ?: return false
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
}
return true
} else {
MediaStore.Images.Media.insertImage(context.contentResolver, bitmap, "title", "desc")
return true
}
}
fun saveFile2Gallery(context: Context, url: String): Boolean {
if (true) {
//返回出一个URI
val insert = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
/*
这里可以默认不写 默认保存在
*/
ContentValues()
) ?: return false //为空的话 直接失败返回了
//这个打开了输出流 直接保存图片就好了
context.contentResolver.openOutputStream(insert).use { os ->
os ?: return false
var x = download(url, os)
return x
}
return false
} else {
val externalFilesDir =
context.getExternalFilesDir(Environment.DIRECTORY_DCIM) ?: return false
var name = "${System.currentTimeMillis()}.jpg"
val file = File(externalFilesDir, name)
//下载文件到应用目录
download(url, file.outputStream())
MediaStore.Images.Media.insertImage(
context.contentResolver,
file.absolutePath,
name,
"desc"
)
//刷新相册
context.sendBroadcast(
Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.fromFile(File(file.getPath()))
)
)
return true
}
}
fun saveFile2Gallery2(context: Context, url: String): Boolean {
val name = System.currentTimeMillis().toString()
val photoPath = Environment.DIRECTORY_DCIM + "/Camera"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, photoPath)//保存路径
put(MediaStore.MediaColumns.IS_PENDING, true)
}
}
//返回出一个URI
val insert = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
) ?: return false
//这个打开了输出流 直接保存图片就好了
context.contentResolver.openOutputStream(insert).use { os ->
os ?: return false
var x = download(url, os)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.MediaColumns.IS_PENDING, false)
}
return x
}
return false
}
fun saveBitmap2Gallery2(context: Context, bitmap: Bitmap): Boolean {
val name = System.currentTimeMillis().toString()
val photoPath = Environment.DIRECTORY_DCIM + "/Camera"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, photoPath)//保存路径
put(MediaStore.MediaColumns.IS_PENDING, true)
}
}
val insert = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
) ?: return false //为空的话 直接失败返回了
//这个打开了输出流 直接保存图片就好了
context.contentResolver.openOutputStream(insert).use {
it ?: return false
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.MediaColumns.IS_PENDING, false)
}
return true
}
private fun download(url: String, os: OutputStream): Boolean {
val url = URL(url)
(url.openConnection() as HttpURLConnection).also { conn ->
conn.requestMethod = "GET"
conn.connectTimeout = 5 * 1000
if (conn.responseCode == 200) {
conn.inputStream.use { ins ->
val buf = ByteArray(2048)
var len: Int
while (ins.read(buf).also { len = it } != -1) {
os.write(buf, 0, len)
}
os.flush()
}
return true
} else {
return false
}
}
}
}
本文地址:https://blog.csdn.net/qq_40990280/article/details/107409504
上一篇: android应用调用系统拨打电话
下一篇: 王通:2019年10个微商小趋势
推荐阅读
-
Android保存多张图片到本地的实现方法
-
android保存Bitmap图片到指定文件夹示例
-
Android读取本地照片和视频相册实例代码
-
Android实现保存图片到本地并在相册中显示
-
js保存图片到手机相册怎么保存(js实现下载文件到本地)
-
Android项目实战(五十八):Android 保存图片文件到本地,相册/图库查看不到的处理
-
Android下保存简单网页到本地(包括简单图片链接转换)实现代码
-
Android拍照保存在系统相册不显示的问题解决方法
-
Android使用phonegap从相册里面获取照片(代码分享)
-
Android--解决图片保存到相册显示1970年1月1日 8:00的问题