更多内容请访问:与华为官方共建的Harmonyos技术社区https://harmonyos.51cto.com目录指南原理和知识点移植到鸿蒙指南本文基于https://gitee.com/andych008/timber_ohos分析一下Timber的源码以及移植到鸿蒙需要做的工作。JakeWharton的Timber是我写日志的最爱,我几乎在所有项目中都使用它。当然,我一般都是通过Timber来使用Logger。原因很简单,因为Timber的界面简洁,Logger的输出风格漂亮。常规套路:FormatStrategyformatStrategy=PrettyFormatStrategy.newBuilder().tag("DwGG")//(Optional)Globaltagforeverylog.DefaultPRETTY_LOGGER.build();Logger.addLogAdapter(newAndroidLogAdapter(formatStrategy));Timber.plant(newTimber.DebugTree(){@Overrideprotectedvoidlog(intpriority,Stringtag,Stringmessage,Throwablet){Logger.log(priority,tag,message,t);}});当然,它的内部实现也很完善。我们往下看。PrincipleTimber翻译成英文为**“木材”**。静态方法Timber.plant(Treetree)是种一棵树。每棵树都有日志功能。例如树A表示向控制台输出日志,树B表示向文件输出日志,树C表示向网络输出日志。在代码实现上,Timber采用了门面模式。树类是外观类。Timber通过plant方法持有Tree类的一个实例,Timber中的asTree和tag方法将其暴露出来。对于调用者来说,取决于抽象类Tree,而不是Tree的具体实现。如果要替换或增加一个Tree类实例,只需要调用plant等相关方法即可,所有调用者不需要在使用Tree对象的地方做任何改动。这是面向对象依赖倒置原则的一个很好的体现。此外,还使用了委托模式。树TREE_OF_SOULS将所有操作委托给forestAsArray。更详细的分析请看Timber源码分析Timber源码分析及相关知识点总结知识点1.临时标签的实现方法很简单,Timber.tag("临时标签").d(xxx);设置一个临时标签。使用一次并移除。为了性能,使用ThreadLocal以空间换取时间。publicstaticabstractclassTree{finalThreadLocalexplicitTag=newThreadLocal<>();StringgetTag(){Stringtag=explicitTag.get();if(tag!=null){explicitTag.remove();}returntag;}}publicstaticclassDebugTreeextendsTree{@OverridefinalStringgetTag(){Stringtag=super.getTag();if(tag!=null){returntag;}//不要将this切换到Thread.getCurrentThread().getStackTrace().Thetestwillpass//因为RobolectricrunsthemontheJVMbutonAndroidtheelementsaredifferent.StackTraceElement[]stackTrace=newThrowable().getStackTrace();if(stackTrace.length<=CALL_STACK_INDEX){thrownewIllegalStateException("Syntheticsstacktracedidn'thaveenoughelements:areyouusingproguard?");}returncreateStackElementTag(stackTrace[CALL_STACK_INDEX]);}2.synchronized的使用,因为以FOREST为单例,所以对其他阅读要加锁。3.staticvolatileTree[]forestAsArray,volatile保证可见性4.关于forestAsArray在plant(Treetree)method=FOREST.toArray(newTree[FOREST.size()]);publicstaticvoidplant(@NotNullTreetree){if(tree==null){thrownewNullPointerException("tree==null");}if(tree==TREE_OF_SOULS){thrownewIllegalArgumentException("CannotplantTimberintoitself.");}synchronized(FOREST){FOREST。添加(树);forestAsArray=森林。toArray(newTree[FOREST.size()]);}}为什么List要转成Tree[]数组?解释这个问题可以参考CopyOnWriteArrayList,线程安全的ArrayList的深入分析!从使用场景来看,Timber适合ListFOREST读多写少,所以只对写操作加锁,读操作(遍历时)不需要加锁。本质上是读写分离的思想,类似CopyOnWriteArrayList,也是为了性能。为什么使用List.toArray(T[]a)而不是List.toArray()?不建议使用不带参数的toArray()方法。该方法的返回值只能是Object[]类。如果强制,会出现ClassCastException错误。移植到鸿蒙如果Timber默认不提供DebugTree,直接在鸿蒙上使用即可。DebugTree树的能力就是在Logcat中输出日志。那么移植需要做的就是将android.util.Log替换成ohos.hiviewdfx.HiLog。HiLog在tag的基础上扩展了HiLogLabel的概念。label=newHiLogLabel(HiLog.DEBUG,0,tag);如果每次都创建一个新的标签,效率太低了,所以可以在这里进行优化。比如和上次一样,就用上一次。或者使用对象池技术。关键字代码:publicstaticclassDebugTreeextendsTree{privatefinalThreadLocalcurrentLabel=newThreadLocal<>();privatefinalThreadLocalcurrentTag=newThreadLocal<>();@Overrideprotectedvoidlog(intpriority,Stringtag,@NotNullStringmessage,Throwablet){HiLogLabel=getHiLogLabel(getHiLogLabel=newThreadLocal<>())(message.length()