保存图片到系统相册,以及修改、删除本应用保存在系统相册的图片 原创
上篇通过AVStorage访问系统相册帖子 https://harmonyos.51cto.com/posts/7399 中,我是通过一段android代码完成的系统数据库插入,因为当时还没有找到鸿蒙写入媒体数据库的方法,经过几天的测试和摸索,基本已经弄清楚鸿蒙媒体数据库增删改查的方法,下面就来讲一下鸿蒙系统如何保存图片到系统相册,以及修改、删除本应用保存在系统相册的图片。
AVStorage公开出来的媒体数据库表字段确实很少,我们能直接拿来用的只有下面这些:
但是在上篇访问相册的代码中,我们循环遍历媒体数据,在query返回的resultSet中,我们可以通过断点找到其中Cursor所带的所有Column名称:
看到这里,我们发现,安卓媒体数据库的字段,实际上鸿蒙都有,只不过没有开出常量方便我们调用,但是我们自己通过字符串的形式来访问这些字段也是完全没有问题的,接下来,我们就可以模仿安卓插入媒体数据库的方法,来写鸿蒙的代码,首先,写文件还需要用到ohos.permission.WRITE_USER_STORAGE权限,config.json权限配置如下:
"reqPermissions": [
{"name": "ohos.permission.READ_USER_STORAGE"},
{"name": "ohos.permission.WRITE_USER_STORAGE"}
]
同样,需要动态申请这两个权限:
String[] permissions = {"ohos.permission.READ_USER_STORAGE", "ohos.permission.WRITE_USER_STORAGE"};
requestPermissionsFromUser(permissions, 0);
获取到权限之后,就可以通过代码保存图片到系统相册了,我们媒体数据库的增删改查都需要用到DataAbilityHelper和AVStorage:
private void saveImage(String fileName, PixelMap pixelMap) {
try {
ValuesBucket valuesBucket = new ValuesBucket();
valuesBucket.putString(AVStorage.Images.Media.DISPLAY_NAME, fileName);
valuesBucket.putString("relative_path", "DCIM/");
valuesBucket.putString(AVStorage.Images.Media.MIME_TYPE, "image/JPEG");
//应用独占
valuesBucket.putInteger("is_pending", 1);
DataAbilityHelper helper = DataAbilityHelper.creator(this);
int id = helper.insert(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, valuesBucket);
Uri uri = Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, String.valueOf(id));
//这里需要"w"写权限
FileDescriptor fd = helper.openFile(uri, "w");
ImagePacker imagePacker = ImagePacker.create();
ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions();
OutputStream outputStream = new FileOutputStream(fd);
packingOptions.format = "image/jpeg";
packingOptions.quality = 90;
boolean result = imagePacker.initializePacking(outputStream, packingOptions);
if (result) {
result = imagePacker.addImage(pixelMap);
if (result) {
long dataSize = imagePacker.finalizePacking();
}
}
outputStream.flush();
outputStream.close();
valuesBucket.clear();
//解除独占
valuesBucket.putInteger("is_pending", 0);
helper.update(uri, valuesBucket, null);
} catch (Exception e) {
e.printStackTrace();
}
}
image.setPixelMap(ResourceTable.Media_icon);
saveImage("test", image.getPixelMap());
这样,我们就把一个鸿蒙应用的icon保存到了DCIM目录下,并且插入了媒体数据库,可以直接在相册看到这张图片:
这里要注意的是,"relative_path"和"is_pending"都是模仿安卓写法在列名中找到的对应字段,分别表示相对路径和是否应用独占,is_pending设置为1时表示只有该应用能访问此图片,其他应用无法发现该图片,当图片处理操作完成后再吧is_pending设置为0,解除独占,让其他应用可见。鸿蒙的helper.insert方法和安卓的contentResolver.insert方法有所不同,安卓方法直接返回一个uri,我们就可以拿来直接操作,而鸿蒙方法返回官方描述是Returns the index of the inserted data record,这个index我的理解就是id,因此,我们需要自己在后面拼出文件的uri再进行操作。获取到uri后,安卓通过contentResolver.openOutputStream(uri)就能获取到输出流来写文件,而鸿蒙没有提供这样的方法,我们就只能通过uri获取FileDescriptor,再通过FileDescriptor生成输出流打包编码成新的图片文件,这里helper.openFile方法一定要有“w”写模式,不然会报FileNotFound的错误。
然后,我们可以通过update方法来对该媒体文件进行更新操作:
private void update(Uri uri) {
DataAbilityHelper helper = DataAbilityHelper.creator(this);
ValuesBucket valuesBucket = new ValuesBucket();
valuesBucket.putString(AVStorage.Images.Media.DISPLAY_NAME, "testReName");
try {
helper.update(uri, valuesBucket, null);
} catch (DataAbilityRemoteException e) {
e.printStackTrace();
}
}
Uri uri = Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, "12");
update(uri);
这里记录的是之前插入的那张图片id,修改更新需要指定文件uri,这里对之前的文件进行了重命名:
最后,再来进行删除操作:
private void deleteAll() {
DataAbilityHelper helper = DataAbilityHelper.creator(this);
try {
ResultSet resultSet = helper.query(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, null, null);
while (resultSet != null && resultSet.goToNextRow()) {
int id = resultSet.getInt(resultSet.getColumnIndexForName(AVStorage.Images.Media.ID));
Uri uri = Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, String.valueOf(id));
helper.delete(uri, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
这里遍历查询媒体数据库,对查询出来的uri进行delete操作,因为模拟器里面就只有我刚插入的图片,所以这里也就删除了刚才的那张图片:
需要注意的是,更新和删除只能对本应用创建的文件进行操作,除非是系统级别的应用可以具有删除和修改其他应用的图片和多媒体文件,否则都会报android.app.RecoverableSecurityException这个异常,哪怕同一个应用重新安装,也不能操作该应用上次安装创建的文件,不知道这个问题是否是因为debug包没有签名而被认为是不同应用导致的。
至此,媒体数据库的增删改查方法基本已经交代清楚了。
(此文章是本人之前在鸿蒙论坛发的贴子,我会把之前的文章先挪过来,今后关于鸿蒙的技术文章会转移到此处,附上原文链接
https://developer.huawei.com/consumer/cn/forum/topic/0201477821844090003?fid=0101303901040230869)