解决HarmonyOS应用中Image组件白块问题的有效方案

描述

概述

在HarmonyOS应用开发过程中,通过Image组件加载网络图片时,通常会经历四个关键阶段:组件创建、图片资源下载、图片解码和刷新。当加载的图片资源过大时,Image组件会等待图片数据下载和解码完成后才刷新显示。由于图片下载过程耗时较长,在图片完全加载之前,页面往往会显示空白区域或占位图(通常为白色或浅色背景),这种现象被称为“Image 白块”。“Image 白块”不仅影响视觉效果,还会降低用户体验,因此在开发中应尽量避免这种情况。

Image

图1 Image白块问题效果图

为了减少图片加载时出现的白块问题,开发者可以采用预下载和缓存机制。具体来说,可以在组件创建之前,通过网络请求将图片下载并解码,然后将图片数据缓存到应用沙箱中。当Image组件加载时,首先检查应用沙箱中是否存在该图片的缓存数据。如果缓存存在,则直接从缓存中读取图片,避免重复下载;如果缓存不存在,再进行网络请求并下载图片。通过这种方式,可以有效减少加载大尺寸网络图片时的白屏或白块现象,缩短加载时间,从而提升用户体验。

Image

图2 Image加载网络图片两种方式对比 

场景案例

在使用Navigation组件时,开发者通常会在主页引入子页面组件,并通过按钮点击实现页面跳转。如果子页面需要加载较大的网络图片,且未设置占位图,则跳转后可能会出现长时间的白块现象。为了解决这一问题,可以在父页面提前下载图片并缓存到本地。当子页面加载时,直接从缓存中读取图片数据,从而减少白块显示时间,提升用户体验。

本文将以应用沙箱提前缓存举例,给出减少Image白块出现时长的一种优化方案。

优化前:使用Image组件直接加载网络地址

以下为部分示例代码:

 

 

NavDestination() {
  Row() {
    // 不推荐用法:使用Image直接加载网络图片的方式,受到图片下载与解析的耗时影响,极易出现白块。
    Image("https://www.example.com/xxx.png") // 此处请填写一个具体的网络图片地址。
      .objectFit(ImageFit.Auto)
      .width('100%')
      .height('100%')
  }
  .width('100%')
  .height('100%')
  .justifyContent(FlexAlign.Center)
}
.title(this.name)
优化后:子页面PageOne中需展示一张较大的网络图片,在父组件的aboutToAppear()中提前发起网络请求,并做判断文件是否存在,已下载的不再重复请求,存储在应用沙箱中。当父页面点击按钮跳转子页面PageOne,此时触发pixMap请求读取应用沙箱中已缓存解码的网络图片并存储在LocalStorage中,通过在子页面的Image中传入被@StorageLink修饰的变量ImageData进行数据刷新,图片送显。

Image

 

 

图3 使用预下载的方式,由开发者灵活地处理网络图片,减少白块出现时长。

以下为关键示例代码:

1.在父组件里aboutToAppear()中提前发起网络请求,当父页面点击按钮跳转子页面PageOne,此时触发pixMap请求读取应用沙箱中已缓存解码的网络图片并存储在localStorage中。非首次点击时,不再重复调用getPixMap(),避免每次点击都从沙箱里读取文件。

 

 

aboutToAppear(): void {
  httpRequest(); // 在父组件提前发起网络请求
}


build() {
  Navigation(this.childNavStack) {
    Column() {
      Button('push Path to pageOne', { stateEffect: true, type: ButtonType.Capsule })
        .width('80%')
        .height(40)
        .margin({ bottom: '36vp' })
        .onClick(() => {
          if (!localStorage.get('imageData')) { // 非首次点击,不再重复调用getPixMap(),避免每次点击都从沙箱里读取文件。
            this.getPixMap();
          }
          this.childNavStack.pushPath({ name: 'pageOne' });
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.End)
  }
  .backgroundColor(Color.Transparent)
  .title('ParentNavigation')
}
2.在NetRequest.ets中定义网络请求httpRequest(),通过fs.access()检查文件是否存在,当文件存在时不再重复请求,并写入沙箱中。
export async function httpRequest() {
  fs.access(fileUrl, fs.AccessModeType.READ).then((res) => { // 检查文件是否存在
    if (!res) { // 如沙箱里不存在地址,重新请求网络图片资源
      http.createHttp()
        .request('https://www.example.com/xxx.png', // 此处请填写一个具体的网络图片地址。
          (error: BusinessError, data: http.HttpResponse) => {
            if (error) {
              // 下载失败时不执行后续逻辑
              return;
            }
            // 处理网络请求返回的数据
            if (http.ResponseCode.OK === data.responseCode) {
              const imageData: ArrayBuffer = data.result as ArrayBuffer;
              // 保存图片到应用沙箱
              readWriteFileWithStream(imageData);
            }
          }
        )
    }
  })
}
3.在子组件中通过在子页面的Image中传入被@StorageLink修饰的变量ImageData进行数据刷新,图片送显。
build() {
  NavDestination() {
    Row() {
      Image(this.imageData) // 正例:此时Image拿到已提前加载好的网络图片,减少了白块出现时长
        .objectFit(ImageFit.Auto)
        .width('100%')
        .height('100%')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
  .title(this.name)
}

 

 

性能对比分析

1、trace分析

下面,使用trace对优化前后性能进行对比分析。

优化前查看trace数据,分析阶段的起点为父页面点击按钮开始计时即trace的H:DispatchTouchEvent,结束点为子页面图片渲染的首帧出现即H:CreateImagePixelMap标签后的第一个Vsync,记录白块出现时间为1.3s,其中以H:HttpRequestInner的标签起始为起点到H:DownloadImageSuccess标签结束为终点记录时间,即为网络下载耗时1.2s,因此使用Image直接加载网络图片时,出现长时间Image白块,其原因是需要等待网络下载资源完成。

Image

图4 直接使用Image加载网络数据 

优化后查看trace数据,分析阶段的起点为父页面点击按钮开始计时即trace的H:DispatchTouchEvent,结束点为子页面图片渲染的首帧出现即H:CreateImagePixelMap标签后的第一个Vsync,记录白块出现时间为32.6ms,其中记录H:HttpRequestInner的标签耗时即为提前网络下载的耗时1.16s,对比白块时长可知提前预下载可以减少白块出现时长。

Image

图5 使用预下载的方式 

说明:网络下载耗时实际受到网络波动影响,优化前后的网络下载耗时数据总体差异在1s内,提供的性能数值仅供参考。

2、效果对比

 

优化前直接使用Image加载网络数据,未使用预下载 优化后使用预下载
 

Image

   

Image

 

 

3、数据对比

对比数据如下:

 

方案 白块出现时长(毫秒) 白块出现时长
(优化前)直接使用Image加载网络数据,未使用预下载 1300 图片位置白块出现时间较长
(优化后)使用预下载 32.6 图片位置白块出现时间较短

 

说明:测试数据仅限于示例程序,不同设备特性和具体应用场景的多样性,所获得的性能数据存在差异,提供的数值仅供参考。

由此可见,加载网络图片时,使用预下载,提前处理网络请求并从应用沙箱中读取缓存数据的方式,可以减少用户可见Image白屏或白块出现时长,提升用户体验。

更详细内容请参考:https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-image-white-lump-solution-V5
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分