鸿蒙开源第三方组件——日志工具组件Timber_ohos

白日放歌须纵酒,青春作伴好还乡。这篇文章主要讲述鸿蒙开源第三方组件——日志工具组件Timber_ohos相关的知识,希望能为你提供帮助。
前言
基于安卓平台的日志工具组件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。

鸿蒙开源第三方组件——日志工具组件Timber_ohos

文章图片

图1 测试界面UI图
2、Log打印
Timber类的静态方法调用如图2中的(a)图所示。运行项目后查看HiLog显示,可以看到实时打印出来的日志,如图2中的(b)图所示。
鸿蒙开源第三方组件——日志工具组件Timber_ohos

文章图片

鸿蒙开源第三方组件——日志工具组件Timber_ohos

文章图片

图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: ohos: ohos:orientation="vertical" ohos:padding="32vp" ohos:background_element="#ffffff" ohos:alignment="horizontal_center"> < Text//“测试”提示 ohos: ohos: ohos:layout_alignment="horizontal_center" ohos:text="Timber测试" ohos:text_size="35fp"/> < Button//控制按钮 ohos: ohos: ohos: 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所示。
鸿蒙开源第三方组件——日志工具组件Timber_ohos

文章图片

图3 调用顺序图
下面我们着重介绍树(Tree类)在Library中的实现,核心算法prepareLog()内部的逻辑结构这两个方面的内容。
1.树(Tree)的实现
Tree类是一种概念形式的日志操作,具体可分为(DebugTree、ReleaseTree、FileTree等)。而在Library内部,Tree类也实现了一系列方法,以便于对森林中的各类树进行增加、删除、修改等操作。
(1)在Timber_ohos组件中维护一个森林对象(FOREST)。
【鸿蒙开源第三方组件——日志工具组件Timber_ohos】森林对象由不同类型的日志树组合而成,并提供对外的接口进行日志的打印。每种类型的树都可以通过种植操作来把自己添加到森林对象中,或者通过移除操作从森林对象中删除,从而实现该类型日志记录的开启和关闭。
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所示:
鸿蒙开源第三方组件——日志工具组件Timber_ohos

文章图片

图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); }

项目贡献人
陈丛笑 郑森文 朱伟 陈美汝 蔡志杰

想了解更多关于鸿蒙的内容,请访问:
51CTO和华为官方战略合作共建的鸿蒙技术社区
https://harmonyos.51cto.com/#bkwz

    推荐阅读