HarmonyOS 鸿蒙Next 刷新相册

发布于 1周前 作者 htzhanglong 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 刷新相册

保存图片到相册后,相册没有显示保存的图片,退出app后相册才显示保存的图片 怎么主动通知刷新相册

2 回复

保存图片到相册是没有延时的,系统相册不需要刷新。以下是相关demo参考:

import { common } from '@kit.AbilityKit';

import { fileUri, picker } from '@kit.CoreFileKit';

import fs from '@ohos.file.fs';

import { photoAccessHelper } from '@kit.MediaLibraryKit';

import { dataSharePredicates } from '@kit.ArkData';

import { image } from '@kit.ImageKit';

import { BusinessError } from '@kit.BasicServicesKit';

import { promptAction } from '@kit.ArkUI';

// 打包 PixelMap 为 jpg 格式

export async function packingPixelMap2Jpg(pixelMap: PixelMap): Promise<ArrayBuffer> {

  // 创建ImagePacker实例

  const imagePackerApi = image.createImagePacker();

  // 设置打包参数

  // format:图片打包格式,只支持 jpg 和 webp

  // quality:JPEG 编码输出图片质量

  // bufferSize:图片大小,默认 10M

  const packOpts: image.PackingOption = { format: "image/jpeg", quality: 100 };

  let imageBuffer: ArrayBuffer = new ArrayBuffer(1);

  try {

    // 图片压缩或重新打包

    imageBuffer = await imagePackerApi.packing(pixelMap, packOpts);

  } catch (err) {

    console.error(`Invoke packingPixelMap2Jpg failed, err: ${JSON.stringify(err)}`);

  }

  return imageBuffer;

}

@Entry

@Component

struct SavePhotoPage {

  @State imagePath: string = ''

  @State pixelMap:image.PixelMap  | undefined = undefined

  private context = getContext(this) as common.UIAbilityContext;

  @Styles ButtonStyle(){

    .width(150).height(35).margin(8)

  }

  build() {

    Row() {

      Column() {

        Button("选择图片").ButtonStyle()

          .onClick(() => {

            this.selectPhoto()

          })

        Button("保存到文件管理器").ButtonStyle()

          .onClick(() => {

            this.imageWriteFileManager(this.imagePath)

          })

        Row(){

          Button("保存到相册方法一").ButtonStyle()

            .onClick(() => {

              this.imageWriteAlbumExample(this.imagePath)

            })

          Button("保存到相册方法二").ButtonStyle()

            .onClick(() => {

              this.imageWriteAlbumExample2(this.imagePath)

            })

        }

        Image(this.pixelMap)

          .width(300)

          .height(320)

        SaveButton().onClick(async (event:ClickEvent, result:SaveButtonOnClickResult) => {

          if (result == SaveButtonOnClickResult.SUCCESS) {

            try {

              const context = getContext(this);

              let helper = photoAccessHelper.getPhotoAccessHelper(context);

              // onClick触发后10秒内通过createAsset接口创建图片文件,10秒后createAsset权限收回。

              let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png');

              // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制

              let resFile = fs.openSync(this.imagePath, fs.OpenMode.READ_ONLY)

              let file = fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

              // 写入文件

              fs.copyFileSync(resFile.fd, file.fd);

              // 关闭文件

              fs.closeSync(file.fd);

              fs.closeSync(resFile.fd);

              promptAction.showToast({

                message: '已保存至相册',

                duration: 2500

              });

            } catch (error) {

              console.error("error is "+ JSON.stringify(error));

            }

          }

        })

      }.width('100%')

    }.height('100%')

  }

  selectPhoto() {

    const photoSelectOptions = new picker.PhotoSelectOptions();

    const photoViewPicker = new picker.PhotoViewPicker();

    photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE

    photoSelectOptions.maxSelectNumber = 5; // 选择媒体文件的最大数目

    photoViewPicker.select(photoSelectOptions).then(async (photoSelectResult: picker.PhotoSelectResult) => {

      const fileUri = photoSelectResult.photoUris[0]

      //复制到沙箱路径,模拟用户下载图片到沙箱

      this.imagePath = this.getFileInfo(fileUri)

      //转为pixelmap保存

      const imageSource: image.ImageSource = image.createImageSource(this.imagePath);

      this.pixelMap = await imageSource.createPixelMap();

    })

  }

  getFileInfo(filePathString: string): string {

    let resFile = fs.openSync(filePathString, fs.OpenMode.READ_ONLY)

    const dateStr = (new Date().getTime()).toString()

    // 临时文件目录

    let newPath = this.context.filesDir + `/${'Temp'+ resFile.name}`;

    // 转化路径

    fs.copyFileSync(resFile.fd, newPath);

    fs.closeSync(resFile.fd);

    // 新的路径

    let realUri = 'file://' + newPath;

    console.log(realUri)

    return realUri

  }

  async imageWriteAlbumExample(fileUri?:string,pixelMap?:image.PixelMap) {

    console.info('createAssetDemo');

    let context = getContext(this);

    let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);

    let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE;

    let extension:string = 'jpg';

    let options: photoAccessHelper.CreateOptions = {

      title: 'testPhoto'

    }

    let uri = await phAccessHelper.createAsset(photoType, extension, options);

    // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制

    try {

      if(pixelMap){

        let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

        const imageBuffer = await packingPixelMap2Jpg(pixelMap as image.PixelMap)

        // 写到媒体库文件中

        fs.writeSync(file.fd, imageBuffer);

        fs.closeSync(file.fd);

      }

      else {

        // 写到媒体库文件中

        let resFile = fs.openSync(fileUri, fs.OpenMode.READ_ONLY)

        let stat = fs.statSync(resFile.fd)

        console.debug("stat size: "+ stat.size)

        let file =  fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

        // 内容复制到媒体库文件中

        fs.copyFileSync(resFile.fd, file.fd);

        fs.closeSync(file.fd);

        fs.closeSync(resFile.fd);

      }

      promptAction.showToast({

        message: '已保存至相册',

        duration: 2500

      });

    }

    catch (err) {

      console.error("error is "+ JSON.stringify(err))

      promptAction.showToast({

        message: '保存失败',

        duration: 2000

      });

    }

  }

  async  imageWriteAlbumExample2(fileUri:string) {

    console.info('createImageAssetRequestDemo:' + fileUri);

    let context = getContext(this);

    try {

      // 需要确保fileUri对应的资源存在

      let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);

      let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(context, fileUri);

      await phAccessHelper.applyChanges(assetChangeRequest);

      console.info('apply createVideoAssetRequest successfully');

      promptAction.showToast({

        message: '已保存至相册',

        duration: 2500

      });

    } catch (err) {

      console.error(`createVideoAssetRequestDemo failed with error: ${err.code}, ${err.message}`);

      promptAction.showToast({

        message: '保存失败',

        duration: 2000

      });

    }

  }

  async  imageWriteFileManager(fileUri:string) {

    let saveUris: Array<string> = [];

    let titleStr = 'testImage'+ new Date().getTime() + '.jpg'

    try {

      const photoSaveOptions = new picker.PhotoSaveOptions(); // 创建文件管理器保存选项实例

      photoSaveOptions.newFileNames = [titleStr]; // 保存文件名(可选),方括号里的文件名自定义,每次不能重复,设备里已有这个文件的话,名字就需要改个不一样的,不然接口会报错

      const photoViewPicker = new picker.PhotoViewPicker();

      try {

        let photoSaveResult = await photoViewPicker.save(photoSaveOptions);

        if (photoSaveResult != undefined) {

          saveUris = photoSaveResult;

          console.info('photoViewPicker.save to file succeed and uris are:' + photoSaveResult);

          let photoSelect = fs.openSync(fileUri, fs.OpenMode.READ_ONLY);

          let photoSave = fs.openSync(saveUris[0], fs.OpenMode.WRITE_ONLY);

          fs.copyFileSync(photoSelect.fd, photoSave.fd);

          fs.close(photoSelect);

          fs.close(photoSave);

          promptAction.showToast({

            message: '已保存至文件管理器',

            duration: 2500

          });

        }

      } catch (error) {

        let err: BusinessError = error as BusinessError;

        console.error(`[picker] Invoke photoViewPicker.save failed, code is ${err.code}, message is ${err.message}`);

        promptAction.showToast({

          message: '保存失败',

          duration: 2000

        });

      }

    } catch (error) {

      let err: BusinessError = error as BusinessError;

      console.info("[picker] photoViewPickerSave error = " + JSON.stringify(err));

    }

  }

}

方便发下你这种实现方式的完整的demo

请参考以下demo(要在module.json5文件中添加ohos.permission.WRITE_IMAGEVIDEO权限):

import componentSnapshot from '@ohos.arkui.componentSnapshot'

import image from '@ohos.multimedia.image'

import { photoAccessHelper } from '@kit.MediaLibraryKit'

import fs from '@ohos.file.fs';

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';

import { BusinessError } from '@ohos.base';

import { common } from '@kit.AbilityKit';

const permissions: Array<Permissions> = ['ohos.permission.WRITE_IMAGEVIDEO'];

function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗

atManager.requestPermissionsFromUser(context, permissions).then((data) => {

let grantStatus: Array<number> = data.authResults;

let length: number = grantStatus.length;

for (let i = 0; i < length; i++) {

if (grantStatus[i] === 0) {

// 用户授权,可以继续访问目标操作

} else {

// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限

return;

}

}

// 授权成功

}).catch((err: BusinessError) => {

console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);

})

}

@Entry

@Component

struct Index {

@State pixmap: image.PixelMap | undefined = undefined

aboutToAppear(): void {

const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;

reqPermissionsFromUser(permissions, context);

}

build() {

Column() {

Row() {

Image(this.pixmap).width(200).height(200).border({ color: Color.Black, width: 2 }).margin(5)

Image($r('app.media.img'))

.autoResize(true)

.width(200)

.height(200)

.margin(5)

.id("root")

}

Button("click to generate UI snapshot")

.onClick(() => {

componentSnapshot.get("root")

.then((pixmap: image.PixelMap) => {

this.pixmap = pixmap

//保存到相册

let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 };

const imagePackerApi = image.createImagePacker();

imagePackerApi.packing(pixmap, packOpts).then(async (buffer: ArrayBuffer) => {

try {

const context = getContext(this)

let helper = photoAccessHelper.getPhotoAccessHelper(context)

let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png')

let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

await fs.write(file.fd, buffer);

// 关闭文件

await fs.close(file.fd);

} catch (error) {

console.error("error is " + JSON.stringify(error))

}

}).catch((error: BusinessError) => {

console.error('Failed to pack the image. And the error is: ' + error);

})

}).catch((err: Error) => {

console.log("error: " + err)

})

}).margin(10)

}

.width('100%')

.height('100%')

.alignItems(HorizontalAlign.Center)

}

}

更多关于HarmonyOS 鸿蒙Next 刷新相册的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS 鸿蒙Next系统中,刷新相册的操作通常依赖于系统内置的相册应用或第三方应用的行为。以下是一些基本的步骤和方法,用于在鸿蒙Next系统上尝试刷新相册:

  1. 手动刷新

    • 打开相册应用。
    • 在相册列表或图库界面,下拉屏幕尝试手动刷新。部分应用可能支持这种快速刷新操作。
  2. 重启相册应用

    • 关闭相册应用,然后从应用列表中重新打开。这有助于清除应用的缓存并重新加载相册内容。
  3. 检查文件同步

    • 如果你的相册内容与云存储服务同步,确保网络连接正常,并检查云服务的同步状态。有时同步延迟可能导致相册内容未及时更新。
  4. 检查文件路径

    • 确保新添加的照片或视频已保存在相册应用能够扫描到的默认存储位置。如果照片保存在自定义文件夹中,可能需要手动导入或调整相册应用的扫描设置。
  5. 系统更新

    • 检查鸿蒙Next系统是否有更新。有时系统更新包含对相册应用的改进和修复。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!