8

HarmonyOS - 本地相册的纠葛

 3 years ago
source link: https://os.51cto.com/article/703004.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
HarmonyOS - 本地相册的纠葛-51CTO.COM
HarmonyOS - 本地相册的纠葛
作者:庄茂裕 2022-03-02 15:59:37
前几天有个同事问我如何把图片存在系统相册的图片,当时我就懵逼了,鸿蒙的好像真的不怎么懂?而且这个操作在我们平时开发时也经常用到,所以搞起。

999228d77e6be905d468453c38d232d85dec59.png

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

二月再见,三月你好,阳春三月万物复苏,愿一切美好都如约而至。携手共创,鸿蒙社区。前几天有个同事问我如何把图片存在系统相册的图片,当时我就懵逼了,鸿蒙的好像真的不怎么懂?而且这个操作在我们平时开发时也经常用到,所以搞起。

52edb538837221b13550975bdfaab22ff89b0f.gif

应该官网有介绍吧,去官网看看,发现是有一丢丢介绍

附上链接:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-data-mgmt-storage-0000001050994909

都说安卓和鸿蒙差不多,应该思路是差不多的吧,于是找到一片文章(https://harmonyos.51cto.com/posts/10568)里面有MediaStore类,用于操作系统媒体数据库的类,鸿蒙确实也有个类似的类AVStorage,但是现在开放的功能不如MediaStore强大。

后面发现是鸿蒙的设计思路有点像ios的,每个应用的都有独自沙河目录,每个app的数据都存储在当前的应用当中,这样大大的确保数据的隐蔽性和安全性,这样比安卓安全性好很多。

保存图片到系统相册

demo布局:

//展示图片
<Image
    ohos:id="$+id:show_photo"
    ohos:height="200fp"
    ohos:width="200fp"
    ohos:image_src="$media:empty"
    ohos:scale_mode="zoom_center"
    ohos:top_margin="30fp"
    /> 
 //选择图片     
<Text
    ohos:id="$+id:select_photo"
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:background_element="$graphic:background_ability_main"
    ohos:layout_alignment="horizontal_center"
    ohos:text="选择图片"
    ohos:text_size="20vp"
    ohos:top_margin="10fp"
    />
  //保存图片
<Text
    ohos:top_margin="10fp"
    ohos:id="$+id:save_photo"
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:background_element="$graphic:background_ability_main"
    ohos:layout_alignment="horizontal_center"
    ohos:text="保存图片"
    ohos:text_size="20vp"
    />

效果如图:

874a77521501959a1a8127ba83c725596a3cbe.jpg

267ee251544f9aba251934d5b21b41e44c04e3.png

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。

 //保存图片到相册 fileName文件名  PixelMap 图片数据
private void saveImageToLibrary(String fileName, PixelMap pixelMap) {
    try {
        ValuesBucket valuesBucket = new ValuesBucket();
        //文件名
        valuesBucket.putString(AVStorage.Images.Media.DISPLAY_NAME, fileName);
       //相对路径
        valuesBucket.putString("relative_path", "DCIM/");
       //文件格式,类型要一定要注意要是JPEG,PNG类型不支持
        valuesBucket.putString(AVStorage.Images.Media.MIME_TYPE, "image/JPEG");
        //应用独占:is_pending设置为1时表示只有该应用能访问此图片,其他应用无法发现该图片,当图片处理操作完成后再吧is_pending设置为0,解除独占,让其他应用可见
        valuesBucket.putInteger("is_pending", 1);       
      //鸿蒙的helper.insert方法和安卓的contentResolver.insert方法有所不同,安卓方法直接返回一个uri,我们就可以拿来直接操作,而鸿蒙方法返回官方描述是Returns the index of the inserted data record(返回插入的数据记录的索引),这个index我的理解就是id,因此,我们需要自己在后面拼出文件的uri再进行操作
        DataAbilityHelper helper = DataAbilityHelper.creator(this);
        int index = helper.insert(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, valuesBucket);
        Uri uri = Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, String.valueOf(index));     
        //获取到uri后,安卓通过contentResolver.openOutputStream(uri)就能获取到输出流来写文件,而鸿蒙没有提供这样的方法,我们就只能通过uri获取FileDescriptor,再通过FileDescriptor生成输出流打包编码成新的图片文件,这里helper.openFile方法一定要有“w”写模式,不然会报FileNotFound的错误。
        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();
    }
}

c6b673372cf0711dc6f702764daf92bc2a5a6a.gif

读取本地相册图片

在config.json中配置读取文件权限(ohos.permission.READ_USER_STORAGE)

"reqPermissions": [{"name": "ohos.permission.READ_USER_STORAGE"}]

在ability中手动申请权限

String[] permissions = {"ohos.permission.READ_USER_STORAGE"};
requestPermissionsFromUser(permissions, 0);

弹出数据来源选择框,获取数据来源的方式。

//选择图片
 private void selectPhoto() {
        //调起系统的选择来源数据视图
        Intent intent = new Intent();
        Operation opt=new Intent.OperationBuilder().withAction("android.intent.action.GET_CONTENT").build();
        intent.setOperation(opt);
        intent.addFlags(Intent.FLAG_NOT_OHOS_COMPONENT);
        intent.setType("image/*");
        startAbilityForResult(intent, imgRequestCode);
    }

效果如图:

e75d85278f16cdb31092015ddc752421725624.jpg

下面是选择图片的回调,imgRequestCode字段的是自定义的,必须是int的类型,这个字段是和上面的selectPhoto()方法里面的imgRequestCode是一致的,根据这个imgRequestCode来判断是否从选择图片的回调回来的,

/*选择图片回调*/
@Override
protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
    if(requestCode==imgRequestCode && resultData!=null)
    {
        //选择的Img对应的Uri
        String chooseImgUrl=resultData.getUriString();
        //定义数据能力帮助对象
        DataAbilityHelper helper=DataAbilityHelper.creator(getContext());
        //定义图片来源对象
        ImageSource imageSource = null;
        //获取选择的Img对应的Id
        String chooseImgId=null;
        //如果是选择文件则getUriString结果为dataability:///com.android.providers.media.documents/document/image%3A437,其中%3A437是":"的URL编码结果,后面的数字就是image对应的Id
        //如果选择的是图库则getUriString结果为dataability:///media/external/images/media/262,最后就是image对应的Id
        //这里需要判断是选择了文件还是图库
        if(chooseImgUri.lastIndexOf("%3A")!=-1){
            chooseImgId = chooseImgUri.substring(chooseImgUri.lastIndexOf("%3A")+3);
        }
        else {
            chooseImgId = chooseImgUri.substring(chooseImgUri.lastIndexOf('/')+1);
        }
        //获取图片对应的uri,由于获取到的前缀是content,我们替换成对应的dataability前缀
        Uri uri=Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI,chooseImgId);
        try {
            //读取图片
            FileDescriptor fd = helper.openFile(uri, "r");
            imageSource = ImageSource.create(fd, null);
            //创建位图
            PixelMap pixelMap = imageSource.createPixelmap(null);
            //设置图片控件对应的位图
            photo.setPixelMap(pixelMap);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (imageSource != null) {
                imageSource.release();
            }
        }
    }
}

官网现有文档不多,开发鸿蒙的时候遇到很多问题,有安卓基础的小伙伴可以参考安卓的思路去解决,应该可以事半功倍,希望本次分享对大家有所帮助。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

03f1e5560e4d7f36e974882e0295375a2dd07c.jpg

责任编辑:jianghua 来源: 鸿蒙社区
zanpc.bd208a1.pngzanpchover.fdd60ba.png
weixin.23cd8b3.png 分享到微信
weibo.16d6b4f.png 分享到微博

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK