前言
在上一篇中我们已经讲述了AndroidQ(10)分区存储适配,包括如何在私有目录创建文件及文件夹
、公共目录下创建文件夹及文件
、公有目录下读取文件
、删除文件
等重要功能。
本篇文章将以开发中的实际情况出发,讲述在AndroidQ中如何将图片下载到公共目录,简单来说就是如何将文件图片复制到另一个文件夹下。
触发场景:gilde已经将图片缓存在本地,获取图片所在的gilde缓存路径,将图片复制到自己指定的目录~
网络下载图片同理复制图片,只是传入不同类型的输入输出流而已~
相关系列文章
- AndroidQ(10)分区存储完美适配
- AndroidQ(10)分区存储完美适配之图片(文件)上传
- AndroidQ(10)分区存储完美适配之图片(文件)下载保存本地
- AndroidQ(10)分区存储完美适配之图片压缩并保存
实际操作上手
必要参数:原文件地址、需要复制的本地uri
-
根据系统版本获取不同的文件路径
- AndroidQ以下,可以使用
File API
操作
/** * AndroidQ以下 * 创建图片缓存路径 * * @param fileName 名称 包含文件类型 * @return 返回file类型 */ public static File getImageFileCache (String fileName) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return null; } //创建项目图片公共缓存目录 File file = new File(Environment.getExternalStorageDirectory()+ File.separator + Environment.DIRECTORY_PICTURES + File.separator + "testAndroidQ" + File.separator + "images";); if (! file.exists()) { file.mkdirs(); } //创建对应图片的缓存路径 return new File(file + File.separator + fileName); }
- AndroidQ以上, 使用
MediaStore
生成对应文件图片缓存路径。不支持File API
直接访问本地文件,如果使用会报无权限访问异常。
/** * AndroidQ以上保存图片到公共目录 * * @param imageName 图片名称 * @param imageType 图片类型 * @param relativePath 缓存路径 */ private static Uri insertImageFileIntoMediaStore (String imageName, String imageType, String relativePath) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { return null; } if (TextUtils.isEmpty(relativePath)) { return null; } Uri insertUri = null; ContentResolver resolver = context.getContentResolver(); //设置文件参数到ContentValues中 ContentValues values = new ContentValues(); //设置文件名 values.put(MediaStore.Images.Media.DISPLAY_NAME, imageName); //设置文件描述,这里以文件名代替 values.put(MediaStore.Images.Media.DESCRIPTION, imageName); //设置文件类型为image/* values.put(MediaStore.Images.Media.MIME_TYPE, "image/" + imageType); //注意:MediaStore.Images.Media.RELATIVE_PATH需要targetSdkVersion=29, //故该方法只可在Android10的手机上执行 values.put(MediaStore.Images.Media.RELATIVE_PATH, relativePath); //EXTERNAL_CONTENT_URI代表外部存储器 Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //insertUri表示文件保存的uri路径 insertUri = resolver.insert(external, values); return insertUri; }
- AndroidQ以下,可以使用
-
通过两个路径地址生成对应的输入输出流
主要方式获取
ContentResolver.openOutputStream(insertUri)
public static boolean copyFile (String sourceFilePath, final Uri insertUri) {
if (insertUri == null) {
return false;
}
ContentResolver resolver = context.getContentResolver();
InputStream is = null;//输入流
OutputStream os = null;//输出流
try {
os = resolver.openOutputStream(insertUri);
if (os == null) {
return false;
}
File sourceFile = new File(sourceFilePath);
if (sourceFile.exists()) { // 文件存在时
is = new FileInputStream(sourceFile); // 读入原文件
//输入流读取文件,输出流写入指定目录
return copyFileWithStream(os, is);
}
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 利用输入输出流边读边写,将文件(图片)写入指定路径
private static boolean copyFileWithStream (OutputStream os, InputStream is) {
if (os == null || is == null) {
return false;
}
int read = 0;
while (true) {
try {
byte[] buffer = new byte[1444];
while ((read = is.read(buffer)) != - 1){
os.write(buffer, 0, read);
os.flush();
}
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
try {
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
AndroidQ以下获取文件输入输出流就不贴代码了,注意区分就好啦~
加载本地图片
我们项目中使用的是Glide
加载,故示例代码中也使用Glide
。
GlideApp.with(context).load(imageUri);
如果AndroidQ之前使用file://
类型加载,兼容10可以采用file转uri的方式,都可以通过uri加载图片。
图片上传
注意:
-
在AndroidQ中公有目录访问文件,
File API
都无法访问,即:file://本地path操作文件
,本地加载图片、上传、下载都不支持,只能通过uri来操作 -
如果下载图片到公共目录,无需再发送广播通知图片更新;
-
MediaStore.Images.Media.RELATIVE_PATH
需要targetSdkVersion=29
,故该方法只可在Android10的手机上执行,如果在小于29的系统下调用RELATIVE_PATH
会报错:
android.database.sqlite.SQLiteException: table files has no column named relative_path (code 1 SQLITE_ERROR)
数据库中插入无法找到relative_path字段
本篇代码适用于文件读写、复制、保存图片到本地等等功能,灵活掌握ContentResolver
大佬点个赞再走呗~后续会继续对AndroidQ分区存储实际操作做总结,欢迎关注~
网友评论