HarmonyOS 应用开发-应用异常处理案例

介绍

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

效果图预览

使用说明

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

实现思路

  1. 构建应用异常。
 handleOperate(index: number) {
    switch (index) {
      case 0:
      // 在按钮点击函数中构造一个APP_CRASH场景,触发应用崩溃事件
        const result: object = JSON.parse('');
        break;
      case 1:
      // 在按钮点击函数中构造一个APP_FREEZE场景,触发应用卡死事件,500ms之后执行无限循环
        while (true) {
        }
    }
  }
  1. 应用退出后,进入本页面,等待订阅消息通知,待收到订阅消息后,通过EventSubscription.ets中的onReceive函数,接收到异常信息数据,
    并通过AppStorage.setOrCreate(‘appEventGroups’,异常信息数据)双向绑定异常信息
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将数据信息加载到页面上。

@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
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>): void {
    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) {
      const code = (err as BusinessError).code;
      const 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):void {
    logger.info(`getFaultMessage start`);
    try {
      // TODO:知识点:通过dataPreferencesManager.get方法获取异常信息数据
      const promise = dataPreferencesManager.get('faultMessage', []);
      promise.then(async (data: dataPreferences.ValueType) => {
        if (typeof data === 'string') {
          const 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                  // 视图层-应用异常页面

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助: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://qr18.cn/F781PH

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分享|创业老阳推荐的Temu蓝海项目到底怎么样?

在当今竞争激烈的创业市场中&#xff0c;寻找一个具有潜力的蓝海项目成为了众多创业者的梦想。近日&#xff0c;创业老阳推荐的Temu蓝海项目引起了广泛关注。那么&#xff0c;这个项目到底怎么样呢?让我们一起来探讨一下。 首先&#xff0c;Temu蓝海项目在定位上具有显著优势 …

【数组】【最长距离】使循环数组所有元素相等的最少秒数

本文涉及知识点 数组 最长距离 LeetCode2808. 使循环数组所有元素相等的最少秒数 给你一个下标从 0 开始长度为 n 的数组 nums 。 每一秒&#xff0c;你可以对数组执行以下操作&#xff1a; 对于范围在 [0, n - 1] 内的每一个下标 i &#xff0c;将 nums[i] 替换成 nums[i] …

吴恩达深度学习 (week1,2)

文章目录 1、神经网络监督学习2、深度学习兴起原因3、深度学习二元分类4、深度学习Logistic 回归5、Logistic 回归损失函数6、深度学习梯度下降法7、深度学习向量法8、Python 中的广播9、上述学习总结10、大作业实现:rocket::rocket:&#xff08;1&#xff09;训练初始数据&…

初识Python(注释、编码规范、关键字...)

&#x1f947;作者简介&#xff1a;CSDN内容合伙人、新星计划第三季Python赛道Top1 &#x1f525;本文已收录于Python系列专栏&#xff1a; 零基础学Python &#x1f4ac;订阅专栏后可私信博主进入Python学习交流群&#xff0c;进群可领取Python视频教程以及Python相关电子书合…

2024年软考考纲改版后考试难度如何?

请注意&#xff1a;2024年软考只有两个资格的考纲发生了变化&#xff0c;分别是系统集成项目管理工程师&#xff08;中项&#xff09;和信息系统监理师&#xff0c;而且变化将在2024年下半年开始执行。其它资格的考纲保持不变&#xff01; 准备参加软考或者已经在备考的考生们…

什么时候考虑使用全局状态管理?vue获取全局状态变量一共有三种方法,你真的理解吗?

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、场景二、设置state中的变量三、直接访问state中的变量四、通过getters访问变量五、通过actions访问变量六、总结总结 前言 本文给大家做个参考&#xff0c;什么时候会考虑使用全局状态管理&#xff1f;以及帮助大家理…

vue+springboot实现JWT登录验证

目录 前言概念实际演示路由信息初始访问登录界面登录验证验证过期 vue实现依赖引入main.js获取和设置token工具类登录方法实体登录方法axios请求 router配置 springboot实现依赖引入JWT工具类忽视jwt验证注解拦截器逻辑跨域&调用拦截器配置登录接口&验证token接口 结语…

初识SpringMVC

一、什么是MVC MVC是一种软件架构模式&#xff08;是一种软件架构设计思想&#xff0c;不止Java开发中用到&#xff0c;其它语言也需要用到&#xff09;&#xff0c;它将应用分为三块&#xff1a; M&#xff1a;Model&#xff08;模型&#xff09;V&#xff1a;View&#xff08…

自定义类型:结构体,位端

结构体内存对齐 结构体的对齐规则&#xff1a; 1. 第一个成员在与结构体变量偏移量为0的地址处。 2. 其他成员变量要对齐到某个数字&#xff08;对齐数&#xff09;的整数倍的地址处。 对齐数 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8 Linux中没有默…

【Shell】各种条件语句的使用——test语句、if语句、case语句

Shell条件语句的使用 条件语句 Shell条件语句的使用条件测试的语法字符串测试表达式整数二元比较操作符逻辑操作符 if的条件语句的语法if的嵌套case语句语法 条件测试的语法 语法1&#xff1a;test <测试表达式> 利用test命令进行条件测试表达式的方法。test命令与<测…

外包干了25天,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

深入浅出 -- 系统架构之微服务标准组件及职责

我们来认识一下微服务架构在Java体系中依托哪些组件实现的。 相对于单体架构的简单粗暴&#xff0c;微服务的核心是将应用打散&#xff0c;形成多个独立提供的微服务&#xff0c;虽然从管理与逻辑上更符合业务需要。但微服务架构也带来了很多急需解决的核心问题&#xff1a; 1…

从“危”到“机”:HubSpot如何助企业转化出海营销CRM风险?

在全球化的大背景下&#xff0c;越来越多的企业选择出海拓展业务&#xff0c;以寻求更大的发展空间。然而&#xff0c;随着市场的扩大&#xff0c;企业在出海营销过程中也面临着各种风险。为了有效规避这些风险&#xff0c;许多企业选择借助HubSpot这样的专业营销软件。今天运营…

软文写作技巧,媒介盒子揭秘

数字化时代,想要获取用户的注意力难上加难&#xff0c;只有紧跟互联网的创作节奏&#xff0c;在软文写作中,根据用户的浏览偏好进行适当调整,让软文具有更高的审美性、易读性和启示性,才能有效地吸引当下受众的注意力。今天媒介盒子就来和大家聊聊软文写作技巧。 一、文章选题 …

C语言之自定义类型联合和枚举

目录 前言 一&#xff1a;联合体&#xff08;共用体&#xff09;union 1.联合体类型的声明 2.联合体的特点 3.联合体大小的计算 4.联合体判断机器的大小端 二&#xff1a;枚举enum 1.概念 2.枚举的优点 3.枚举的使用 接下来的日子会顺顺利利&#xff0c;万事胜意…

深度学习500问——Chapter06: 循环神经网络(RNN)(2)

文章目录 6.4 CNN和RNN的区别 6.5 RNNs与FNNs有什么区别 6.6 RNNs训练和传统ANN训练异同点 6.7 为什么RNN训练的时候Loss波动很大 6.8 标准RNN前向输出流程 6.9 BPTT算法推导 6.9 RNN中为什么会出现梯度消失 6.10 如何解决RNN中的梯度消失问题 6.4 CNN和RNN的区别 类别特点描述…

2014最新AIGC创作系统ChatGPT网站源码+AI绘画网站源码+GPT4-All联网搜索模型

一、文章前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持…

【超简单】基于PaddleSpeech搭建个人语音听写服务

一、【超简单】之基于PaddleSpeech搭建个人语音听写服务 1.需求分析 亲们,你们要写会议纪要嘛?亲们,你们要写会议纪要嘛?亲们,你们要写会议纪要嘛?当您面对成吨的会议录音,着急写会议纪要而不得不愚公移山、人海战术?听的头晕眼花,听的漏洞百出,听的怀疑人生,那么你…

电脑网卡无法连接网络?三招教你解决问题

在现代生活中&#xff0c;电脑网卡扮演着连接互联网的关键角色。无论是有线网卡还是无线网卡&#xff0c;都是电脑与外部网络通信的重要途径。然而&#xff0c;有时候我们可能会遇到电脑网卡无法连接网络的问题&#xff0c;这会严重影响我们的工作和娱乐。本文将介绍三种常见的…