介绍

本示例介绍了通过应用事件打点hiAppEvent获取上一次应用异常信息的方法,主要分为应用崩溃、应用卡死以及系统查杀三种。

效果图预览

使用说明

  1. 点击构建应用崩溃事件,3s之后应用退出,然后打开应用进入应用异常页面,隔1min左右后,显示上次异常退出信息。
  2. 点击构建应用卡死事件,需手动退出,然后打开应用进入应用异常页面,隔1min左右后,显示上次异常退出信息。

实现思路

  1. 构建应用异常。源码参考ApplicationException.ets
 handleOperate(index: number) {
switch (index) {
case 0:
// 在按钮点击函数中构造一个APP_CRASH场景,触发应用崩溃事件
let result: object = JSON.parse('');
break;
case 1:
// 在按钮点击函数中构造一个APP_FREEZE场景,触发应用卡死事件,500ms之后执行无限循环
while (true) {
}
}
}
  1. 应用退出后,进入本页面,等待订阅消息通知,待收到订阅消息后,通过EventSubscription.ets中的onReceive函数,接收到异常信息数据, 并通过AppStorage.setOrCreate('appEventGroups',异常信息数据)双向绑定异常信息,源码参考代码可参考EventSubscription.ets
import hiAppEvent from '@ohos.hiviewdfx.hiAppEvent';
import { logger } from '@ohos/base'; const TAG: string = 'eventSubscription'; export function eventSubscription() {
// 添加应用事件观察者方法,可用于订阅应用事件
hiAppEvent.addWatcher({
// 开发者可以自定义观察者名称,系统会使用名称来标识不同的观察者
name: "mst",
// 开发者可以订阅感兴趣的系统事件,此处是订阅了崩溃事件
appEventFilters: [
{
domain: hiAppEvent.domain.OS,
names: [hiAppEvent.event.APP_CRASH, hiAppEvent.event.APP_FREEZE]
}
],
// TODO:知识点:获取事件组信息。开发者可以自行实现订阅实时回调函数,以便对订阅获取到的事件数据进行自定义处理
onReceive: async (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
logger.info(TAG, `HiAppEvent onReceive: domain=${domain}`);
// 获取事件组信息,与ApplicationException文件中的@StorageLink('faultMessage') faultMessage进行双向数据绑定
AppStorage.setOrCreate('appEventGroups', appEventGroups);
}
});
}
  1. @StorageLink('appEventGroups')接收订阅事件函数传递的事件组信息,调用getFaultMessage函数对信息进行处理,将处理后的信息通过 this.faultDataSource.pushData(message) 添加到懒加载数据源中,并通过this.faultDataSource.persistenceStorage()执行持久化存储,最后通过使用LazyForEach将数据信息加载到页面上。 具体源码参考ApplicationException.ets
@Component
struct FaultArea {
// 懒加载数据源
@State faultDataSource: FaultDataSource = new FaultDataSource();
// 双向数据绑定懒加载数据源的数组长度
@StorageLink('faultDataSourceLength') faultDataSourceLength: number = 0;
// 双向数据绑定事件组,与AppStorage.setOrCreate进行绑定,此变量发生变化触发getFaultMessage函数
@StorageLink('appEventGroups') @Watch('getFaultMessage') appEventGroups: Array<hiAppEvent.AppEventGroup> = [];
@Consume eventIndex: number; async aboutToAppear() {
logger.info(TAG, `aboutToAppear start`);
// 获取Preferences实例
PreferencesManager.getPreferences(this.faultDataSource);
} // 获取应用异常信息
async getFaultMessage() {
logger.info(TAG, `getAppEventGroups start`);
if (this.appEventGroups && this.appEventGroups.length > 0) {
// 遍历事件组
this.appEventGroups.forEach((eventGroup: hiAppEvent.AppEventGroup) => {
// 遍历事件对象集合
eventGroup.appEventInfos.forEach(async (eventInfo: hiAppEvent.AppEventInfo) => {
let message: string = '';
message += `HiAppEvent eventInfo.domain=${eventInfo.domain}\n` // 事件领域
+ `HiAppEvent eventInfo.name=${eventInfo.name}\n` // 事件名称
+ `HiAppEvent eventInfo.eventType=${eventInfo.eventType}\n` // 事件名称
+ `HiAppEvent eventInfo.params.time=${eventInfo.params['time']}\n` // 事件发生的时间
+ `HiAppEvent eventInfo.params.crash_type=${eventInfo.params['crash_type']}\n`
+ `HiAppEvent eventInfo.params.foreground=${eventInfo.params['foreground']}\n`
+ `HiAppEvent eventInfo.params.bundle_version=${eventInfo.params['bundle_version']}\n`
+ `HiAppEvent eventInfo.params.bundle_name=${eventInfo.params['bundle_name']}\n`
+ `HiAppEvent eventInfo.params.exception=${JSON.stringify(eventInfo.params['exception'])}\n`
+ `HiAppEvent eventInfo.params.hilog.size=${eventInfo.params['hilog'].length}\n`;
// TODO:知识点:将异常信息存储到数组faultMessage当中
this.faultDataSource.pushData(message);
})
})
}
// TODO:知识点:持久化存储异常信息集合
this.faultDataSource.persistenceStorage();
} build() {
List() {
// 添加判断,如果异常信息集合的信息条数大于0,遍历异常信息
if (this.faultDataSourceLength > 0) {
// 性能:动态加载数据场景可以使用LazyForEach遍历数据。https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/arkts-rendering-control-lazyforeach-0000001524417213-V3
LazyForEach(this.faultDataSource, (message: string) => {
ListItem() {
Text(message)
.textAlign(TextAlign.Start)
}
}, (item: string) => item)
} else {
ListItem() {
// 根据被点击事件的下标响应指定的信息
Text(this.eventIndex === 0 ? $r('app.string.crash_event_message') :
(this.eventIndex === 1 ? $r('app.string.freeze_event_message') :
(this.faultSign ? $r('app.string.data_delay_toast') :
$r('app.string.no_message'))))
}
}
}
.width('92%')
.height(300)
.shadow(ShadowStyle.OUTER_DEFAULT_SM)
.borderRadius($r('app.string.ohos_id_corner_radius_default_m'))
.padding($r('app.string.ohos_id_card_padding_start'))
}
}
  1. 以上代码中有引用懒加载数据类和持久化存储类,源码可参考DataSource.ets和 PreferencesManager.ets
// DataSource.ets
export class FaultDataSource extends BasicDataSource {
// 懒加载数据
private faultMessage: Array<string> = []; // TODO:知识点:获取懒加载数据源的数据长度
totalCount(): number {
return this.faultMessage.length;
} // 获取指定数据项
getData(index: number): string {
return this.faultMessage[index];
} // TODO:知识点:存储数据到懒加载数据源中
pushData(data: string): void {
this.faultMessage.push(data);
// 在数组头部添加数据
this.notifyDataAdd(this.faultMessage.length - 1);
AppStorage.setOrCreate('faultDataSourceLength', this.totalCount());
} // TODO:知识点:持久化存储异常信息集合
persistenceStorage(): void {
PreferencesManager.putFaultMessage(this.faultMessage);
}
} // PreferencesManager.ets
/**
* 存储数据异常信息
* @param faultMessage 异常信息集合
*/
public static putFaultMessage(faultMessage: Array<string>) {
logger.info(`putMessage start`);
try {
// TODO:知识点:通过 dataPreferencesManager.put方法存储数据
dataPreferencesManager.put('faultMessage', JSON.stringify(faultMessage), async (err: BusinessError) => {
if (err) {
logger.error("Failed to put value of 'faultMessage'. code =" + err.code + ", message =" + err.message);
return;
}
logger.info('Succeeded in putting value of faultMessage.');
dataPreferencesManager.flush();
})
} catch (err) {
let code = (err as BusinessError).code;
let message = (err as BusinessError).message;
logger.error("Failed to put value of 'catch err'. code =" + err.code + ", message =" + err.message);
}
} /**
* 获取数据异常信息
* @param faultMessage 异常信息集合
*/
public static getFaultMessage(faultDataSource:FaultDataSource) {
logger.info(`getFaultMessage start`);
try {
// TODO:知识点:通过dataPreferencesManager.get方法获取异常信息数据
let promise = dataPreferencesManager.get('faultMessage', []);
promise.then(async (data: dataPreferences.ValueType) => {
if (typeof data === 'string') {
let faultData: Array<string> = JSON.parse(data);
// 将异常数据添加到懒加载数据源中
faultData.forEach((item: string) => {
faultDataSource.pushData(item);
})
// 双向数据绑定懒加载数据源长度,更新数据源长度
AppStorage.setOrCreate('faultDataSourceLength',faultDataSource.totalCount())
logger.info('Succeeded in getting value of faultMessage.');
}
})
} catch (err) {
logger.error("Failed to get value of 'catch err'. code =" + err.code + ", message =" + err.message);
}
}

高性能知识点

本示例使用了LazyForEach进行数据懒加载,将叠加获取到的应用异常信息进行渲染。

工程结构&模块类型

aplicationexception                             // har类型
|---model
| |---DataSource.ets // 模型层-懒加载数据源
| |---EventSubscription.ets // 数据模型层-订阅应用事件
| |---MockData.ets // 数据模型层-模拟数据
| |---PreferencesManager.ets // 数据模型层-持久化存储
|---view
| |---PreferencesManager.ets // 视图层-应用异常页面

模块依赖

本实例依赖common模块来实现日志的打印、资源的调用以及公共组件FunctionDescription的引用。

参考资料

应用事件打点HiAppEvent 数据懒加载LazyForEach

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新VIP学习资源,请移步前往小编:https://qr21.cn/FV7h05

HarmonyOS NEXT应用开发之异常处理案例的更多相关文章

  1. bootstrap框架开发电子商城案例

    bootstrap框架开发电子商城案例 玛图 bootstrap 商城框架

  2. Java注解开发与应用案例

    Java注解开发与应用案例 Annotation(注解)是JDK5.0及以后版本引入的,可以对包.类.属性.方法的描述,给被述对象打上标签,被打上标签后的类.属性.方法将被赋予特殊的“功能”:打个比喻 ...

  3. Android开发---网格布局案例

     Android开发---网格布局案例 效果图: 1.MainActivity.java package com.example.android_activity; import android.ap ...

  4. 【iOS开发-56】案例BUG:button的enabled、控件的userInteractionEnabled以及两种提示框UIAlert和UIActionSheet

    接上述案例找BUG:[iOS开发-51]案例学习:动画新写法.删除子视图.视图顺序.延迟方法.button多功能使用方法及icon图标和启动页设置 (1)BUG:答案满了就不能再点击optionbut ...

  5. 2017.11.6 JavaWeb-----第七章 JavaWeb常用开发模式与案例

    JavaWeb-----第七章 JavaWeb常用开发模式与案例 (1)单纯的JSP页面开发模式 通过在JSP中的脚本标记,直接在JSP页面中实现各种功能.称为"单纯的JSP页面编程模式&q ...

  6. python——flask常见接口开发(简单案例)

    python——flask常见接口开发(简单案例)原创 大蛇王 发布于2019-01-24 11:34:06 阅读数 5208 收藏展开 版本:python3.5+ 模块:flask 目标:开发一个只 ...

  7. 大数据开发--Hbase协处理器案例

    大数据开发--Hbase协处理器案例 1. 需求描述 在社交网站,社交APP上会存储有大量的用户数据以及用户之间的关系数据,比如A用户的好友列表会展示出他所有的好友,现有一张Hbase表,存储就是当前 ...

  8. HarmonyOS三方件开发指南(12)——cropper图片裁剪

    鸿蒙入门指南,小白速来!0基础学习路线分享,高效学习方法,重点答疑解惑--->[课程入口] 目录:1. cropper组件功能介绍2. cropper使用方法3. cropper组件开发实现4. ...

  9. HarmonyOS三方件开发指南(13)-SwipeLayout侧滑删除

    鸿蒙入门指南,小白速来!0基础学习路线分享,高效学习方法,重点答疑解惑--->[课程入口] 目录:1. SwipeLayout组件功能介绍2. SwipeLayout使用方法3. SwipeLa ...

  10. HarmonyOS三方件开发指南(14)-Glide组件功能介绍

    <HarmonyOS三方件开发指南>系列文章合集 引言 在实际应用开发中,会用到大量图片处理,如:网络图片.本地图片.应用资源.二进制流.Uri对象等,虽然官方提供了PixelMap进行图 ...

随机推荐

  1. MinimalApis自动注册

    前言 在Asp.Net Core 6 推出了最小 Api(MinimalApis)来简化WebApi的开发,在前后端分离的趋势下越来越多的后端服务只提供Api接口,但是用Controller的开发模式 ...

  2. drf(JWT认证)

    一. jwt实现过程 1. 构建jwt过程 第一: 用户提交用户名和密码给服务端,如果登录成功,使用jwt创建一个token,并给用户返回 eyJ0eXAiOiJqd3QiLCJhbGciOiJIUz ...

  3. Snackbar源码分析

    目录介绍 1.最简单创造方法 1.1 Snackbar作用 1.2 最简单的创建 1.3 Snackbar消失的几种方式 2.源码分析 2.1 Snackbar的make方法源码分析 2.2 对Sna ...

  4. 记录--用 Vue 实现原神官网的角色切换效果

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 为了更好的了解原神角色,我模仿官网做了一个角色切换效果,在做的过程当中也总结了一些技术点. 为了让大家更好的体验,我兼容了 PC 端 ...

  5. 【Docker】Dockerfile基础知识,相信你一定有所收获

    Dockerfile常用命令 FROM: 继承基础镜像 MAINTAINER:镜像制作作者信息 RUN: 用来执行shell命令 EXPOSE: 暴露端口号 CMD: 启动容器默认执行的命令,会被覆盖 ...

  6. 关于tomcat容器抛出的异常解决方案之一

    1,描述 问题类型:调试信息泄露 如: 现要求:前端页面不显示调试信息. 解决方案: 替换默认的tomcat <dependency> <groupId>org.springf ...

  7. Games101--作业2

    说明 该作业主要想实现两个三角形的绘制 绘制结果走样 按照课上所讲的方法,对包围盒里面的所有像素进行判断是否在三角形内,然后着色,这样的结果由于采样频率的问题将导致边缘走样现象的发生 if(!insi ...

  8. 基于 alientek rv1126 快速启动调试那的写坑

    基于 alientek rv1126 快速启动调试那的写坑 1. sdk 编制准备工作 1.1 编译配置修改 首先拿到 sdk 通过修改一下相关配置 1.1.1修改DDR 配置 cd /home/al ...

  9. 从优秀到卓越:成为DevOps专家的7项软技能

    在我的职业生涯中,遇见过许多专业人士,他们在技术上非常健全,对自己的领域和技术有很好的掌握和专业知识,但是由于缺乏软技能,他们错过了晋升.现场机会.高级技术面试以及职业生涯中的机会.很震惊吧,技术好却 ...

  10. 关于 ThreadLocal 你需要知道的几点

    一.ThreadLocal是什么? 一个类对象类型,提供属线程本地变量,也就是同一个变量对不同线程保存了不同的值,但是和线程自身定义的自属变量不同. 通常以私有静态类型定义,用以保存特定线程特定状态属 ...