更多信息请访问:与华为共建的鸿蒙技术社区官方https://harmonyos.51cto.com前言基于Android的日志工具组件Timber平台(https://github.com/JakeWharton/timber),实现鸿蒙的功能迁移和重构。代码已经开源(https://gitee.com/isrc_ohos/timber_ohos),欢迎广大开发者提出宝贵意见。背景Timber_ohos是一个日志工具组件,具有一个小型且可扩展的API。可以为开发者提供统一的API接口来记录不同类型的日志,帮助开发者管理不同类型的日志。同时Timber_ohos是项目开发时的日志开关,通过这个开关来控制日志的打印和关闭,从而形成不同的软件版本。该组件功能丰富,使用方便高效,可广泛应用于软件项目开发。组件效果展示1.测试界面。如图1所示,这是一个简单的UI页面,用于测试Timber_ohos功能。点击“测试”按钮,输出相应的日志。图1测试界面UI图2、日志打印Timber类的静态方法调用如图2(a)所示,运行项目后查看HiLog显示,可以看到实时打印的日志,如图2(b)所示。图2HiLog日志打印示例分析1.树的用法Timber_ohos用树(Tree)的概念来表达不同的日志操作。种一棵树有伐木的作用,种多棵树有多种伐木的作用。有许多类型的树。常见的树有:DebugTree、RealeseTree、FileTree、CrashReportingTree等,这些树都是继承自Tree类。DebugTree:记录所有日志。RealeseTree:只记录warn、error、wtf信息。FileTree:在运行时记录到文件。CrashReportingTree:记录应用程序崩溃时的信息。默认情况下,DebugTree已被种植在Timber_ohos中。由于Timber_ohos本身是一个可扩展的框架,当开发者想要获取其他类型的日志时,需要自己实现一个日志类,然后植入到Timber_ohos中。2.Sample实现Sample部分需要添加日志记录类型,负责整体展示布局的构建。首先为Timber_ohos组件添加任何需要的Tree子类实例(此处使用DebugTree),然后设置一个简单的按钮监听器。按下按钮后,调试日志会出现在鸿蒙的常规HiLog中。下面将详细介绍各组件的使用。步骤1.种一棵树(添加Tree子类的一个实例)。步骤2.创建整体显示布局。Step3.导入相关类,设置按键监听。第4步。使用Tree实例。(1)种树(添加Tree子类实例)这一步是在ExampleApp类的onInitialize()方法中实现的。首先需要创建一个Tree子类的实例,然后调用Timber的plant()方法,将该实例作为plant()方法的参数。这个过程叫做“种树”。Timber.plant(newTimber.DebugTree(0x001f00));复制(2)创建整体显示布局在XML文件中创建一个DirectionalLayout作为整体显示布局,随着父控件的变化调整宽高。创建两个组件,分别是Text组件和Button组件,用于控制组件效果的显示。整体显示布局如图1所示。(3)在MainAbilitySlice中导入显示布局并设置按键监听,整体displaylayout也需要通过super.setUIContent()方法设置才能生效,显示成功。然后为按钮设置点击事件。当用户需要使用Tree子类实例时,可以用手指点击。super.setUIContent(ResourceTable.Layout_ability_main);//设置整体显示布局findComponentById(ResourceTable.Id_btn1).setClickedListener(newComponent.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测试成功!!!");库解析库主要为Timber_ohos组件提供日志输出的统一接口,拿种植的调试树(DebugTree)以Sample为例,当使用Timber的静态方法Timber.e时,从MainAbilitySlice到打印log的Timber.e可以分为5步,整体calling过程如图3所示。图3调用时序图下面我们将着重介绍库中树(Tree类)的实现,核心算法prepareLog()的内部逻辑结构两方面。1.树(Tree)的实现。在Library内部,Tree类还实现了一系列方法,方便对森林中的各种树进行增删改查等操作。(1)在Timber_ohos组件中维护一个森林对象(FOREST)。forest对象由不同类型的日志树组合而成,并对外提供日志打印接口。每种类型的树都可以通过种植操作添加到森林对象中,或者通过移除操作从森林对象中删除,从而实现该类型的登录和退出。privatestaticfinalListFOREST=newArrayList<>();(2)植树。调用plant()方法将Tree实例添加到FOREST。可以种植一棵树或多棵树。这是种树的例子。可以看出,树的种植是在plant()静态方法的synchronized同步代码块中进行的。具体过程是先将树对象添加到FOREST列表中,然后将日志树保存到forestAsArray数组中(将树种到森林中)。需要注意的是,如果树为空,会抛出空指针异常错误;如果开发者手动种植灵魂之树(TREE_OF_SOULS),Timber_ohos会抛出非法数据异常。publicstaticvoidplant(@NotNullTreetree){if(tree==null){thrownewNullPointerException("tree==null");}if(tree==TREE_OF_SOULS){thrownewIllegalArgumentException("CannotplantTimberintoitself.");}synchronized(FOREST){FOREST。add(tree);forestAsArray=FOREST.toArray(newTree[FOREST.size()]);}}(3)移除Tree实例同样,移除树也是在静态方法uproot中的synchronized同步代码块()进行中。如果没有可移除的树,Timber_ohos组件会抛出非法数据异常;否则,Timber_ohos组件将在移除树后根据FOREST列表生成一个新的forestAsArray数组。publicstaticvoiduproot(@NotNullTreetree){synchronized(FOREST){if(!FOREST.remove(tree)){thrownewIllegalArgumentException("Cannotuproottreewhichisnotplanted:"+tree);}forestAsArray=FOREST.toArray(newTree[FOREST.size()]);(4)清除森林中的所有Tree实例要清除森林中的所有Tree实例,首先使用FOREST的clear()方法清除所有Tree实例,会自动生成一个对应的新的Tree数组,forestAsArray就是这个对数组的引用。所以forestAsArray数组被设置为一个空数组。publicstaticvoiduprootAll(){synchronized(FOREST){FOREST.clear();forestAsArray=TREE_ARRAY_EMPTY;}}(5)灵魂之树(TREE_OF_SOULS)估计很多同学对上面的TREE_OF_SOULS很好奇。在代码实现中,这里使用了经典设计模式中的代理模式。TREE_OF_SOULS本质上是一个代理对象。森林中的所有其他普通树对象都是代理对象。代理对象通过for循环依次调用代理对象。实现不同类型日志记录的同名方法,如下所示。privatestaticfinalTreeTREE_OF_SOULS=newTree(){@Overridepublicvoidv(Stringmessage,Object...args){Tree[]forest=forestAsArray;for(Treetree:forest){tree.v(message,args);}}2.核心算法(prepareLog)Timber_ohos组件的logging功能的核心算法在抽象类Tree的私有化prepareLog()方法中,它接收四个参数,如图4所示:图4参数表prepareLog()中,logging的条件先进行判断,然后处理要打印的消息信息,最后调用抽象方法log进行日志输出。总体来说,prepareLog()算法流程如下:(1)获取当前线程的tag。(2)当普通信息消息不为空且消息长度为0时,则普通信息消息为空。(3)当正常信息message和异常信息t均为null时,表示没有信息可记录,方法直接返回。(4)异常信息t通过getStackTraceString方法转化为字符串。(5)通过formatMessage方法将普通信息message和可选的格式化参数args拼装成字符串。(6)调用抽象方法log进行日志记录,由Tree的子类实现。privatevoidprepareLog(intpriority,Throwablet,Stringmessage,Object...args){//获取当前线程的tagStringtag=getTag();//当普通消息message不为null且消息长度为0时,则普通消息messageisnullif(message!=null&&message.length()==0){message=null;}//当正常信息message和异常信息t都为null时,表示没有信息记录,方法直接返回if(message==null){if(t==null){return;//Swallowmessageifit'snullandthere'snothrowable}//通过getStackTraceString方法将异常信息t转换为字符串message=getStackTraceString(t);}else{if(args!=null&&args.length>0){//通过formatMessage方法message=formatMessage(message,args);}if(t!=null){message+="\n"+getStackTraceString(t);}}//调用抽象方法log进行日志记录,该方法由类的子类实现Treelog(priority,tag,message,t);}更多内容请访问:与华为合作共建Harmonyos技术社区https://harmonyos.51cto.com