HarmonyOS NEXT应用开发之异常处理案例

介绍

本示例介绍了通过应用事件打点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-V3LazyForEach(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

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:https://qr21.cn/FV7h05

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

大厂鸿蒙面试题:https://qr21.cn/FV7h05

鸿蒙开发面试大盘集篇(共计319页):https://qr21.cn/FV7h05

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/742982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx启动闪退

在nginx目录下cmd&#xff0c;nginx -t&#xff0c;找到原因是&#xff1a;“在端口80上运行NGINX时&#xff0c;因为端口80是HTTP默认端口&#xff0c;需要管理员权限才能访问” 所以修改端口号&#xff1a; 在nginx.conf文件中&#xff0c;修改listen&#xff1a;80为8080 …

【C++】类的默认成员函数(下)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一、运算符重载1.1 引例1.2 概念及运用&#xff1a;1.3 牛刀小试:1.4 重载1.5 运…

QT TCP通信介绍

QT是一个跨平台的C应用程序开发框架&#xff0c;它提供了一套完整的工具和库&#xff0c;用于开发各种类型的应用程序&#xff0c;包括图形用户界面(GUI)应用程序、命令行工具、网络应用程序等。QT提供了丰富的功能和类来简化网络通信的开发&#xff0c;其中包括TCP通信。 TCP…

C++面试100问!(二)

怎么定义常量的&#xff1f;常量存放在内存的哪个位置&#xff1f; 常量在C里的定义就是一个const加上对象类型&#xff0c;常量定义必须初始化。对于局部对象&#xff0c;常量存放在栈区&#xff0c;对于全局对象&#xff0c;常量存放在全局/静态存储区。对于字面值常量&#…

Linux-轻量级数据库sqlite函数接口-016

1 1.1【sqlite3_open】 1.1.1函数原型 【int sqlite3_open(const char *filename, /* Database filename (UTF-8) */sqlite3 **ppDb /* OUT: SQLite db handle */);】1.1.2函数功能 打开数据库文件(创建一个数据库连接)1.1.3函数参数 【filename】&#xff1a;…

Element Plus与Ant Design Vue:选型对比

在Vue.js的开发过程中&#xff0c;选择合适的UI框架对于项目的成功至关重要。Element Plus和Ant Design Vue作为两个热门的Vue UI框架&#xff0c;各自拥有独特的特点和优势。本文将从多个维度对这两个框架进行对比&#xff0c;帮助开发者在选择时做出明智的决策。 一、框架版…

Python网络基础爬虫-python基本语法

文章目录 逻辑语句if,else,elifforwhile异常处理 函数与类defpassclass 逻辑语句 熟悉C/C语言的人们可能很希望Python提供switch语句&#xff0c;但Python中并没有这个关键词&#xff0c;也没有这个语句结构。但是可以通过if-elif-elif-…这样的结构代替&#xff0c;或者使用字…

目标检测——YOLOv2算法解读

论文&#xff1a;YOLO9000: Better, Faster, Stronger 作者&#xff1a;Joseph Redmon, Ali Farhadi 链接&#xff1a;https://arxiv.org/pdf/1612.08242v1.pdf 代码&#xff1a;http://pjreddie.com/yolo9000/ YOLO系列其他文章&#xff1a; YOLOv1通俗易懂版解读SSD算法解读…

STM32/GD32——CAN协议

说明&#xff1a;本文不断更新中&#xff0c;内容均为作者手打... 芯片选型 Ciga Device — GD32F470系列 CAN协议规则 CAN帧种类介绍 CAN总线以“帧”的方式进行通讯。CAN协议定义了5种类型的帧&#xff1a;数据帧、遥控帧、错误帧、过载帧、间隔帧。其中“数据帧”最为常…

记一次生产慢sql索引优化及思考

记一次生产慢sql索引优化及思考 问题重现 夜黑风高的某一晚&#xff0c;突然收到一条运营后台数据库慢sql的报警&#xff0c;耗时竟然达到了60s。看了一下&#xff0c;还好不是很频繁&#xff0c;内心会更加从容排查问题&#xff0c;应该是特定条件下没有走到索引导致&#x…

如何在数据库中存储小数:FLOAT、DECIMAL还是BIGINT?

前言 这里还是用前面的例子: 在线机票订票系统的数据表设计。此时已经完成了大部分字段的设计&#xff0c;可能如下: CREATE TABLE flights ( flight_id INT AUTO_INCREMENT PRIMARY KEY, flight_number VARCHAR(10), departure_airport_code VARCHAR(3), arrival_ai…

[论文精读]Dynamic Coarse-to-Fine Learning for Oriented Tiny Object Detection

论文网址&#xff1a;[2304.08876] 用于定向微小目标检测的动态粗到细学习 (arxiv.org) 论文代码&#xff1a;https://github.com/ChaselTsui/mmrotate-dcfl 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&…

支付模块-基于消息队列发送支付通知消息

消息队列发送支付通知消息 需求分析 订单服务作为通用服务&#xff0c;在订单支付成功后需要将支付结果异步通知给其他对接的微服务&#xff0c;微服务收到支付结果根据订单的类型去更新自己的业务数据 技术方案 使用消息队列进行异步通知需要保证消息的可靠性即生产端将消息…

深入了解 大语言模型(LLM)微调方法

引言 众所周知&#xff0c;大语言模型(LLM)正在飞速发展&#xff0c;各行业都有了自己的大模型。其中&#xff0c;大模型微调技术在此过程中起到了非常关键的作用&#xff0c;它提升了模型的生成效率和适应性&#xff0c;使其能够在多样化的应用场景中发挥更大的价值。 那么&…

华为新设备升级示例

​ 新设备升级示例 升级前准备工作 准备升级工具&#xff0c;即操作终端PC、网线和串口线。准备所需版本系统软件。 企业用户&#xff1a;登录​​http://support.huawei.com/e​​&#xff0c;在搜索栏中输入交换机型号&#xff0c;单击搜索栏中联想出的路径&#xff0c;进…

服务器命令

服务器命令 服务器命令top查看任务 服务器命令 top查看任务 、ps 命令 ps 命令是最基本同时也是非常强大的进程查看命令。使用该命令可以确定有哪些进程正在运行和它所运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等。总之大部分信息都是可以通过执行…

pytorch模型转onnx格式,编写符号函数实现torch算子接口和onnx算子的映射,新建简单算子--模型部署记录整理

对于深度学习模型来说&#xff0c;模型部署指让训练好的模型在特定环境中运行的过程。相比于软件部署&#xff0c;模型部署会面临更多的难题&#xff1a; 运行模型所需的环境难以配置。深度学习模型通常是由一些框架编写&#xff0c;比如 PyTorch、TensorFlow。由于框架规模、依…

JVM是如何解决跨代引用的?

JVM是如何解决跨代引用的&#xff1f; 跨代引用问题如何解决跨代引用记忆集&#xff08;Remembered Set&#xff09;卡表 写屏障 跨代引用问题 假如要现在进行一次只局限于新生代区域内的收集(Minor gc)&#xff0c;但新生代的对象1在老年代中被引用&#xff0c;为了找出该区域…

掌握Go语言:深入encoding/gob包的高效数据序列化

掌握Go语言&#xff1a;深入encoding/gob包的高效数据序列化 引言理解Gob和它的使用场景Gob的概念和设计目标Gob的适用场景和优势 开始使用Gob基本的Gob编码和解码示例代码编码&#xff08;序列化&#xff09;解码&#xff08;反序列化&#xff09; Gob编码高级应用自定义类型的…

c语言常见上机题

快速排序 快排很容易进入无限递归&#xff0c;写的时候要注意边界问题 #include<iostream>using namespace std;int n;const int N 1e6 10;void qsort(int a[],int l,int r){if(l>r) return;int xa[l],il-1,jr1;while(i<j){do i;while(a[i]<x);do j--;while(…