鸿蒙软件开发用什么框架(鸿蒙开源第三方组件)

前言

基于安卓平台的日志工具组件Timber ( https://github.com/JakeWharton/timber), 实现鸿蒙的功能化迁移和重构。代码已经开源到(https://gitee.com/isrc_ohos/timber_ohos),欢迎各位开发者提出宝贵意见。

背景

Timber_ohos是一个带有小型可扩展API的日志工具组件,它可以给开发者提供统一的API接口,来记录不同类型的日志,帮助开发者管理不同类型的log。同时,Timber_ohos是项目开发时的log开关,通过此开关控制log的打印与关闭,从而形成不同的软件版本。该组件功能丰富且使用简单高效,可以被广泛应用于软件项目开发中。

组件效果展示

1、测试界面。

如图1所示,这是一个为了测试Timber_ohos功能而简单构建的UI页面。点击“测试”按钮即可输出相应的log。

鸿蒙软件开发用什么框架(鸿蒙开源第三方组件)(1)

图1 测试界面UI图

2、Log打印

Timber类的静态方法调用如图2中的(a)图所示。运行项目后查看HiLog显示,可以看到实时打印出来的日志,如图2中的(b)图所示。

鸿蒙软件开发用什么框架(鸿蒙开源第三方组件)(2)

鸿蒙软件开发用什么框架(鸿蒙开源第三方组件)(3)

图2 HiLog日志打印

Sample解析

1、Tree的使用

Timber_ohos将不同的日志操作以树(Tree)的概念进行表示,种植一种树就拥有一种日志记录功能,种植多种树就拥有多种日志记录的功能,树的种类有很多,常见的树有:DebugTree、RealeseTree、FileTree、CrashReportingTree等,这些树都是继承自Tree类。

  • DebugTree:对所有的日志进行记录。
  • RealeseTree:只对 warn,error,wtf 信息进行记录。
  • FileTree:在运行时将日志记录到文件中。
  • CrashReportingTree:对应用崩溃时的信息进行记录。

Timber_ohos中默认已经种植了DebugTree,由于Timber_ohos本身是一个可扩展的框架,因此开发者想得到其他类型的Log日志时,就需要自己实现一个日志记录类 ,然后种植到Timber_ohos中即可。

2 、 Sample的实现

Sample部分需要添加日志记录种类,并负责整体显示布局的搭建。首先为Timber_ohos组件添加想要的任何Tree子类实例(这里使用的是DebugTree),然后设置简单的按钮监听器,当按动按钮时在鸿蒙常规HiLog中出现调试日志。下面将详细介绍组件的使用方法。

步骤1. 种树(添加Tree子类实例)。

步骤2. 创建整体的显示布局。

步骤3. 导入相关类并设置按钮监听。

步骤4. 使用Tree实例。

(1)种树(添加Tree子类实例)

本步骤是在ExampleApp类的onInitialize()方法中实现的。首先需要创建Tree子类实例,然后调用Timber的plant()方法,同时将实例作为plant()方法的参数,这个过程叫做“种树”。

Timber.plant(new Timber.DebugTree(0x001f00));

(2)创建整体的显示布局 在XML文件中创建一个DirectionalLayout作为整体显示布局,宽度和高度都跟随父控件变化而调整。创建两个组件,分别是Text组件和Button组件,用于控制组件效果显示。整体显示布局如图1所示。

<DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:orientation="vertical" ohos:padding="32vp" ohos:background_element="#ffffff" ohos:alignment="horizontal_center"> <Text //“测试”提示 ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:text="Timber测试" ohos:text_size="35fp"/> <Button //控制按钮 ohos:id="$ id:btn1" ohos:height="match_content" ohos:width="match_content" ohos:top_margin="35vp" ohos:text_size="25fp" ohos:background_element="#FF51A8DD" ohos:padding="10vp" ohos:text="测试"/> </DirectionalLayout>

(3)导入显示布局并设置按钮监听

在MainAbilitySlice中,整体显示布局也需要通过super.setUIContent()方法进行设置,才能生效并成功显示。然后给按钮设置点击事件,当用户需要使用Tree子类实例时,可通过手指进行点击。

super.setUIContent(ResourceTable.Layout_ability_main);//设置整体显示布局 findComponentById(ResourceTable.Id_btn1).setClickedListener(new Component.ClickedListener() { ...//按钮的点击事件 }

(4)使用Tree实例

当用户需要打印调试日志的时候,调用Timber的静态方法,就会在鸿蒙常规HiLog上出现调试日志。调试日志如组件效果展示部分的图2所示。

Timber.e ("Timber.e 测试成功!!!"); Timber.d ("Timber.d 测试成功!!!"); Timber.i ("Timber.i 测试成功!!!"); Timber.w ("Timber.w 测试成功!!!"); Timber.wtf ("Timber.wtf测试成功!!!");

Library解析

Library主要为Timber_ohos组件提供日志输出的统一接口。以Sample中种植的调试树(DebugTree)为例,当使用Timber的静态方法Timber.e时,从MainAbilitySlice到Timber.e打印log的地方可以分为5个步骤,整体调用的流程如图3所示。

鸿蒙软件开发用什么框架(鸿蒙开源第三方组件)(4)

图3 调用顺序图

下面我们着重介绍树(Tree类)在Library中的实现,核心算法prepareLog()内部的逻辑结构这两个方面的内容。

1.树(Tree)的实现

Tree类是一种概念形式的日志操作,具体可分为(DebugTree、ReleaseTree、FileTree等)。而在Library内部,Tree类也实现了一系列方法,以便于对森林中的各类树进行增加、删除、修改等操作。

(1)在Timber_ohos组件中维护一个森林对象(FOREST)。

森林对象由不同类型的日志树组合而成,并提供对外的接口进行日志的打印。每种类型的树都可以通过种植操作来把自己添加到森林对象中,或者通过移除操作从森林对象中删除,从而实现该类型日志记录的开启和关闭。

private static final List<Tree> FOREST = new ArrayList<>();

(2)种树。

调用plant()方法,把Tree实例添加进FOREST里面 可以种植一棵树,也可以种植多棵树。这里以种一棵树为例。可以看到,树的种植是在plant()静态方法的synchronized 同步代码块中进行的。具体流程是先将树对象添加到 FOREST 列表中,然后将日志树保存到 forestAsArray 数组中(将树种植到森林中)。

需要注意的是,如果树为空,则抛出空指针异常的错误;如果开发者手动种植灵魂之树(TREE_OF_SOULS),Timber_ohos将会抛出非法数据异常。

public static void plant(@NotNull Tree tree) { if (tree == null) { throw new NullPointerException("tree == null"); } if (tree == TREE_OF_SOULS) { throw new IllegalArgumentException("Cannot plant Timber into itself."); } synchronized (FOREST) { FOREST.add(tree); forestAsArray = FOREST.toArray(new Tree[FOREST.size()]); } }

(3)移除Tree实例

同样的,树的移除也是在静态方法uproot()中的synchronized 同步代码块中进行的。如果没有该树可以移除,则Timber_ohos组件将抛出一个非法数据异常;反之,Timber_ohos组件将根据移除该树后的 FOREST列表生成 新的forestAsArray 数组。

public static void uproot(@NotNull Tree tree) { synchronized (FOREST) { if (!FOREST.remove(tree)) { throw new IllegalArgumentException("Cannot uproot tree which is not planted: " tree); } forestAsArray = FOREST.toArray(new Tree[FOREST.size()]); } }

(4)清除森林里面全部的Tree实例

移除森林里所有的Tree实例,首先使用FOREST的clear()方法清除所有的Tree实例,将会自动生成一个对应的新的Tree数组,而forestAsArray就是这个数组的引用。因此forestAsArray 数组被设置为空数组。

public static void uprootAll() { synchronized (FOREST) { FOREST.clear(); forestAsArray = TREE_ARRAY_EMPTY; } }

(5) 灵魂之树(TREE_OF_SOULS)

估计很多同学好奇上述TREE_OF_SOULS。代码实现中,在这里运用的是经典设计模式中的代理模式,TREE_OF_SOULS 本质上是一个代理对象,森林中所有其他普通的树对象都是被代理对象,代理对象通过 for 循环来依次调用被代理对象的同名方法,从而实现不同类型的日志记录,如下所示。

private static final Tree TREE_OF_SOULS = new Tree() { @Override public void v(String message, Object... args) { Tree[] forest = forestAsArray; for (Tree tree : forest) { tree.v(message, args); } }

2.核心算法( prepareLog)

Timber_ohos组件的日志记录功能的核心算法在抽象类 Tree 的私有化 prepareLog()方法中,该方法接收四个参数,如图4所示:

鸿蒙软件开发用什么框架(鸿蒙开源第三方组件)(5)

图4 参数表

prepareLog()中首先判断了打log的条件,然后将要打印的message信息进行了处理,最后调用了抽象方法log进行日志输出。总体而言 prepareLog()算法流程如下:

(1)获取当前线程的 tag。

(2)当正常信息message不为null且信息长度为0时,这时正常信息message为null。

(3)当正常信息message和异常信息t都是 null 时,说明没有信息可以记录,方法直接返回。

(4)异常信息t通过getStackTraceString方法转换为字符串。

(5)正常信息message和可选格式化参数 args 通过formatMessage方法拼装成一个字符串。

(6)调用抽象方法 log 进行日志记录,这个方法由Tree的子类来实现。

private void prepareLog(int priority, Throwable t, String message, Object... args) { //获取当前线程的 tag String tag = getTag(); //当正常信息message不为null且信息长度为0时,这时正常信息message为null if (message != null && message.length() == 0) { message = null; } //当正常信息 message 和异常信息 t 都是 null 时,说明没有信息可以记录,方法直接返回 if (message == null) { if (t == null) { return; // Swallow message if it's null and there's no throwable. } //异常信息 t 通过 getStackTraceString 方法转换为字符串 message = getStackTraceString(t); } else { if (args != null && args.length > 0) { //正常信息 message 和可选格式化参数 args 通过 formatMessage 方法拼装成一个字符串 message = formatMessage(message, args); } if (t != null) { message = "\n" getStackTraceString(t); } } //调用抽象方法 log 进行日志记录,这个方法由 Tree 的子类来实现 log(priority, tag, message, t); }

项目贡献人

陈丛笑 郑森文 朱伟 陈美汝 蔡志杰

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页