HarmonyOS 鸿蒙Next中悬浮窗加载本地gif资源图片

HarmonyOS 鸿蒙Next中悬浮窗加载本地gif资源图片 运行程序后台日志出现以下e级别错误日志:set ashmem name failed、[Interface] task 18837 apply qos failed, errno = 4。用的是Image组件展示一张只有500多KB的gif图片出现上述日志,但如果展示png、jpg图片就不会显示。


更多关于HarmonyOS 鸿蒙Next中悬浮窗加载本地gif资源图片的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

背景知识:

从日志上看是是因为,Ashmem(共享内存)命名失败,通常因内存资源泄漏或系统限制导致,频繁调用 ImageSource/PixelMap 后未释放资源问题。建议更换 加载gif图片控件。

问题解决:

可以使用 gif-drawable(V2.1.1) 来替换image

示例代码:

import { GIFComponent, ResourceLoader } from '[@ohos](/user/ohos)/gif-drawable';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct GifPage {
    @State message: string = 'Hello World';
    // gif绘制组件用户属性设置
    @State model:GIFComponent.ControllerOptions = new GIFComponent.ControllerOptions();
    // 是否自动播放
    @State gifAutoPlay:boolean = false;
    // 重置GIF播放,每次取反都能生效
    @State gifReset:boolean = true;

    context = this.getUIContext().getHostContext() as common.UIAbilityContext

    build() {
        Column() {
          
           if(this.gifAutoPlay){
               GIFComponent ({
                   model:this.model,
                   autoPlay:this.gifAutoPlay,
                   resetGif: this.gifReset}
               )
                   .width(300)
                   .height(144)
                   .backgroundColor(Color.Gray)
           }else{
               Text("加载中...")
                   .width(300)
                   .height(144)
                   .backgroundColor(Color.Gray)
                   .fontSize(20)
                   .fontColor(Color.Black)
                   .fontWeight(FontWeight.Bold)
                   .textAlign(TextAlign.Center)
           }

            Button("加载gif")
                .width(100)
                .height(50)
                .onClick(()=>{
                  //  1、将资源中的图片信息转为  ArrayBuffer 
                    ResourceLoader.loadMedia(
                        $r("app.media.ic_my_gif").id,
                        this.context).then((buffer)=>{

                            this.model
                                .setSpeedFactor(1.0)
                                .setOpenHardware(true)

                        console.info('ArrayBuffer长度:', buffer?.byteLength);

                        //2、调用这个将数组字节给到方法
                        this.model.loadBuffer(buffer,(err)=>{
                            console.error("error -> "+err)
                            if(!err){
                              //3、切换播放
                                this.gifAutoPlay = true;
                            }
                        })
                    })
                })

        }
        .height('100%')
        .width('100%')
    }
}

真机演示:

cke_10815.gif

更多关于HarmonyOS 鸿蒙Next中悬浮窗加载本地gif资源图片的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这两条日志本质上都更像系统侧解码/调度的告警,而不是你业务代码“加载失败”的直接原因,之所以只在 GIF 出现,核心原因通常是:

1)GIF 虽然只有 500KB,但解码后占用内存可能非常大

GIF 是多帧动画,解码时往往要在内存里展开成多张 RGBA 帧(宽 × 高 × 4 × 帧数),再加上缓冲/合成开销。
所以“文件小 ≠ 内存小”,在悬浮窗(子窗口/浮窗)这种资源更紧的场景下,更容易触发共享内存相关告警。

你看到的:

  • set ashmem name failed:和 ashmem(共享内存) 相关,常见于图像/图形缓冲分配或标记阶段异常(不一定致命,但说明共享内存链路有问题或资源紧张)。
  • apply qos failed, errno = 4:一般是线程 QoS/优先级设置被系统中断(errno=4 常见是 EINTR),多数情况下不影响功能,属于噪声日志。

如果 GIF 仍能正常显示:可以先按“系统噪声日志”处理,线上可接受(E 级别不等于崩溃)。
如果 GIF 显示异常/偶现不显示:大概率就是解码/缓冲资源不足导致的。


2)在悬浮窗里更推荐的替代方案(比 GIF 稳)

方案 A:把 GIF 转成 MP4/WebM,用 Video 播放(最稳、占用更可控)

动效类 UI(加载中/提示动画)用短视频替代 GIF 是最常见优化手段。

方案 B:拆帧成多张 PNG/JPG,用 ImageAnimator 播放

把 GIF 导出成帧序列,然后:

@State frames: Array<{ src: ResourceStr }> = [
  { src: $rawfile('loading_0.png') },
  { src: $rawfile('loading_1.png') },
  // ...
]

build() {
  ImageAnimator()
    .images(this.frames)
    .duration(800)   // 一轮时长
    .iterations(-1)  // 无限循环
}

这通常比直接喂 GIF 给 Image 更可控(你还能降帧/降分辨率)。


3)你可以先做的排查/优化点

  1. 降低 GIF 分辨率/帧数/颜色数(即便 500KB,也可能是高分辨率+多帧)。
  2. 如果你只是需要“动一下”,优先用 MP4 或 ImageAnimator
  3. 确认悬浮窗的窗口背景透明/层级设置没问题(但你说 PNG/JPG 没日志,说明资源路径本身大概率没问题)。

你这个是典型的错误

set ashmem name failed 意思是说匿名共享内存命名失败 这是GIF 特有问题

apply qos failed, errno = 4 意思是GIF 解码在后台线程运行,尝试设置高优先级失败

好知道问题了如何解决

推荐使用三方库 gif-drawable 看图 用起来嘎嘎的 , 如有帮助给个采纳谢谢

cke_1547.png

看日志像是gif图的原因,建议换个gif图试试

在HarmonyOS NEXT中,实现悬浮窗并加载本地GIF资源:使用ImageAnimator组件,设置src$r('app.media.xxx')rawfile路径,stateImageAnimatorState.RUNNINGinterval根据帧率调整。在悬浮窗的页面中声明该组件即可。需在module.json5中申请ohos.permission.SYSTEM_FLOAT_WINDOW权限。

这是由于 HarmonyOS NEXT 悬浮窗沙箱环境对共享内存 (Ashmem) 的限制所致。Image 组件展示 PNG/JPG 仅需解码为静态位图,而 GIF 需持续解析帧序列,底层会尝试通过 Ashmem 传递帧数据并设置 QoS,悬浮窗进程无对应权限,于是出现 set ashmem name failed 和 apply qos failed 报错,导致加载失败。

解决方式:改用帧动画方案,手动解码每一帧并轮播。

  1. 将 GIF 放入 rawfile。
  2. 使用 image.createPixelMap 创建 PixelMap,并逐帧设置索引。
  3. 通过定时器交替更新 Image 组件的 PixelMap。

核心代码:

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

@State imagePixelMap: image.PixelMap | null = null;
private pixelMap: image.PixelMap | undefined;
private intervalId: number = -1;

async playGifInFloating() {
  let rm = getContext().resourceManager;
  let rawFd = await rm.getRawFd('test.gif');
  this.pixelMap = await image.createPixelMap(rawFd);
  let count = this.pixelMap.getFrameCount();
  let index = 0;
  this.intervalId = setInterval(() => {
    this.pixelMap!.setFrameIndex(index);
    this.imagePixelMap = this.pixelMap; // 触发刷新
    index = (index + 1) % count;
  }, 100); // 根据帧间隔调整
}

aboutToDisappear() {
  clearInterval(this.intervalId);
  this.pixelMap?.release();
}

绑定组件:Image(this.imagePixelMap).
注意播放完毕后释放资源,避免内存泄漏。此方式可完美绕过悬浮窗限制。

回到顶部