本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:

ErrorManager助力高效应对AppFreeze问题:Native崩溃日志的AI辅助定位-华为开发者话题 | 华为开发者联盟

前言

       做鸿蒙开发的朋友,大概都收到过这类用户反馈:"点了没反应,但App没闪退"。界面像被定格了一样,应用还活着,就是不响应。这种卡住但不崩溃的情况,就是AppFreeze(应用冻屏)

       传统开发模式下,AppFreeze问题很难定位——开发者只能靠用户描述加零星日志去"猜",效率很低。HarmonyOS其实早就考虑到了这个痛点,提供了ErrorManager错误管理能力,让应用可以主动感知AppFreeze事件并获取现场信息。下面就来看看怎么用。

什么是AppFreeze

       AppFreeze指的是主线程执行任务时超过6秒未响应输入事件或未完成页面刷新,用户感觉界面"卡住"了。和崩溃不同,进程还在,只是主线程被阻塞了。

       常见原因就几种:

   • 主线程干了耗时操作(同步计算、大量数据序列化等)

   • 多线程锁竞争或死锁

   • FFRT任务执行超时

   • libuv EventLoop被阻塞

       AppFreeze发生时系统会生成故障报告,但默认存在本地,开发者没法实时拿到。接下来要介绍的ErrorManager,就是来解决这个问题的。

ErrorManager核心能力一览

       ErrorManager在@kit.AbilityKit包里,提供的接口与AppFreeze相关的主要有这几个:

接口名称

说明

on('freeze', observer)

监听Freeze事件

off('freeze', observer)

取消监听

setDefaultFreezeObserver(observer)

设置Freeze处理器,支持链式调用

       简单说就是,监听AppFreeze和链式处理。

快速接入

第一步:导入模块

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

第二步:定义回调

function freezeCallback() {
    console.error('FreezeHandler', '检测到应用发生冻屏!');
    // Get more diagnostic information here
    // Report to your service quality monitoring platform
}

第三步:注册监听

Button('开启Freeze监听').onClick(() => {
    try {
        errorManager.on('freeze', freezeCallback);
        console.info('Freeze监听已开启');
    } catch (paramError) {
        let code = (paramError as BusinessError).code;
        let message = (paramError as BusinessError).message;
        console.error(`注册失败: ${code}, ${message}`);
    }
});

       三步完成,应用就具备了AppFreeze感知能力。冻屏发生时回调会被触发,里面想做什么都行——存日志、上报监控、尝试恢复都行。

进阶用法:链式处理器

       实际业务中可能需要分几步处理:先保存现场,再尝试恢复,最后如果实在不行就退出。setDefaultFreezeObserver支持链式调用,能实现这种场景。

第一个处理器

let firstHandler: errorManager.FreezeObserver = () => {};

const firstFreezeHandler: errorManager.FreezeObserver = () => {
    console.info('[FirstHandler] 检测到Freeze,开始保存现场...');
    // Save diagnostic information locally
    if (firstHandler) {
        firstHandler(); // Pass to next handler
    }
};

第二个处理器

let secondHandler: errorManager.FreezeObserver = () => {};

const secondFreezeHandler: errorManager.FreezeObserver = () => {
    console.info('[SecondHandler] 尝试恢复应用...');
    // Attempt recovery operation
    if (secondHandler) {
        secondHandler();
    } else {
        console.info('[SecondHandler] 恢复失败,准备退出');
    }
};

注册

function initFreezeHandlers() {
    // Later registered handlers are called first
    errorManager.setDefaultFreezeObserver(firstFreezeHandler);
    errorManager.setDefaultFreezeObserver(secondFreezeHandler);
}

       AppFreeze发生时,后注册的处理器先执行——先是secondHandler尝试恢复,失败了再调用firstHandler保存现场。

配合loopObserver预防Freeze

       除了等AppFreeze发生,还可以主动监控。loopObserver能在主线程处理事件超过设定阈值时提前通知,在问题恶化前介入。

let loopObserver: errorManager.LoopObserver = {
    onLoopTimeOut(timeout: number) {
        console.warn(`主线程处理超时: ${timeout}ms`);
        // Issue hasn't worsened yet, early intervention is possible
    }
};

// Set threshold to 1000ms
errorManager.on('loopObserver', 1000, loopObserver);

       这个适合做"预防性维护"——主线程开始卡的时候就能发现,不用等到真的AppFreeze。

最佳实践

1. 尽早注册:在EntryAbility的onCreate里就注册,避免漏掉早期冻屏事件

2. 回调里同步退出:如果无法恢复,在回调链最后调用process.processManager.exit(0)退出,别让用户对着黑屏发呆

3. 上报诊断信息:时间、堆栈、环境都上报,形成问题分析的数据基础

4. 阈值合理设置:loopObserver阈值建议从1000ms开始调,太短误报多,太长可能错过最佳干预时机

5. 回调保持轻量:回调里别做复杂IO或网络请求,避免连锁反应

常见问题

       Q:ErrorManager和HiAppEvent有什么区别?

       A:ErrorManager是同步回调,AppFreeze发生时会立即通知,适合需要立刻处理的场景;HiAppEvent更像日志归档,适合离线分析。

       Q:AppFreeze监听会影响性能吗?

       A:不会。这是基于系统事件触发的,没有AppFreeze发生就不会有任何开销。

       Q:能注册多个监听器吗?

       A:用on('freeze')注册的监听器相互独立,都会收到回调;用setDefaultFreezeObserver注册的是链式调用,按注册顺序逆序执行。

       Q:接口的使用范围和回调的时长?

       A:只能在主线程使用,且回调有时间限制,不建议做耗时操作,一般耗时1s以内,否则可能会有数据丢失风险。

结语

       AppFreeze是个老问题,但ErrorManager给了开发者一件趁手的工具。实时感知、链式处理、提前预警——把这些能力用起来,至少能知道问题出在哪、什么时候发生的。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐