介绍

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

效果图预览

使用说明

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

实现思路

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

高性能知识点

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

工程结构&模块类型

  1. aplicationexception // har类型
  2. |---model
  3. | |---DataSource.ets // 模型层-懒加载数据源
  4. | |---EventSubscription.ets // 数据模型层-订阅应用事件
  5. | |---MockData.ets // 数据模型层-模拟数据
  6. | |---PreferencesManager.ets // 数据模型层-持久化存储
  7. |---view
  8. | |---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. arch签名出现问题时,无法修复时

    sudo rm -rf /etc/pacman.d/gnupgsudo pacman-key --init sudo pacman-key --populate archlinux && ...

  2. 快速将json装DTO的GsonFormatPlus插件使用

    参考:https://www.jianshu.com/p/8fb0e4274436 https://blog.csdn.net/qq_43039260/article/details/12676582 ...

  3. linux权限、特殊权限、ACL控制

    Linux基本权限 1.权限基本概述 1.什么是权限? 我们可以把它理解为操作系统对用户能够执行的功能所设立的限制,主要用于约束用户能对系统所做的操作,以及内容访问的范围,或者说,权限是指某个特定的用 ...

  4. 应急响应靶机训练-Linux1

    靶机来源: 知攻善防实验室公众号 https://mp.weixin.qq.com/s/gCWGnBiwbqSnafXU1apJCA 我是在另一台主机上通过ssh连接到靶机进行解题的,以下为解题记录. ...

  5. Three.js实现可透视的水面效果

    1. 引言 Three.js是著名的JavaScript 3D图形库,用于浏览器中开发 3D 交互场景的 JS 引擎,可以快速的搭建三维场景 Three.js官网为:创建一个场景 – three.js ...

  6. struts2-66漏洞复现

    Strut2-66漏洞从搭建到复现到原理 0x0 创建JavaEE环境 使用idea创建JavaEE项目,添加Strut2的依赖 点击右上角创建新项目 下一步,依赖项只选择一个Servlet就行了,版 ...

  7. [Spring]aop的配置与使用

    [版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://blog.csdn.net/m0_69908381/article/details/129907717 出自[进步* ...

  8. 【已解决】Hadoop未知的主机名master

  9. LiftPool:双向池化操作,细节拉满,再也不怕丢特征了 | ICLR 2021

    论文参考信号处理中提升方案提出双向池化操作LiftPool,不仅下采样时能保留尽可能多的细节,上采样时也能恢复更多的细节.从实验结果来看,LiftPool对图像分类能的准确率和鲁棒性都有不错的提升,而 ...

  10. #dp#C 公共子序列

    题目 给定两个字符串\(s1,s2\),求它们的\(LCS\) 满足\(|s1|\leq 10^6,|s2|\leq 10^3\) 分析 考场写了\(O(|s1|*|s2|)\)成功TLE, 考虑突破 ...