志在指尖
用双手敲打未来

Android Debug 之 Log 最佳实践

布景
在开发过程中,调试是必不可少的一项工作。
当咱们要确认项目的逻辑时,当咱们要了解界面的生命周期时,当咱们发现新写的逻辑与期望作用不一致时,当咱们觉得数据有问题时……
而调试有两种办法:
第一种便是运用debug模式运转APP,然后经过断点让程序运转到指定方位进行分析。
第二种便是打日志的办法,经过观察输出来确认程序是否运转到该方位以及此刻的数据。
本篇文章首要聚集在第二种办法上面。
Android里边,打日志运用的体系API是Log,你以为直接运用就完了吗?
封装
假定你在需求打印日志的当地直接运用体系的API,那么当遇到下面状况时,会「牵一发而动全身」。
场景一:假如我打印日志要用三方库的日志API,那么我要查找项目一切运用方位,并一一替换。
场景二:假如我期望在开发环境下打印日志,release环境不打印,这个时候每个方位都需求单独做处理。
因而咱们需求在运用Log进行日志打印之前,做一层封装。android
假定咱们的类姓名为ZLog,代码如下:
importandroid.util.Log;/**
*Createdon2019-10-26
*
*@authorZengyu.Zhan
*/publicclassZLog{publicstaticintv(Stringtag,Stringmsg){returnLog.v(tag,msg);
}publicstaticintd(Stringtag,Stringmsg){returnLog.d(tag,msg);
}publicstaticinti(Stringtag,Stringmsg){returnLog.i(tag,msg);
}publicstaticintw(Stringtag,Stringmsg){returnLog.w(tag,msg);
}publicstaticinte(Stringtag,Stringmsg){returnLog.e(tag,msg);
}
}
这样处理之后,关于场景一和场景二,咱们需求修改的仅仅ZLog这个类,而不需求到详细运用ZLog的一切当地去修改。
供给日志打印操控
咱们知道,日志打印或许包含灵敏信息,并且过多的日志打印或许影响APP的功能,因而咱们一般是在开发时候打开日志,在发布APP之前关闭。
因而咱们这边需求供给一个标志位来操控日志的打印与否。
importandroid.util.Log;/**
*Createdon2019-10-26
*
*@authorZengyu.Zhan
*/publicclassZLog{privatestaticbooleanisDebugMode=false;publicstaticvoidsetDebugMode(booleandebugMode){
isDebugMode=debugMode;
}publicstaticintv(Stringtag,Stringmsg){returnisDebugMode?Log.v(tag,msg):-1;
}publicstaticintd(Stringtag,Stringmsg){returnisDebugMode?Log.d(tag,msg):-1;
}publicstaticinti(Stringtag,Stringmsg){returnisDebugMode?Log.i(tag,msg):-1;
}publicstaticintw(Stringtag,Stringmsg){returnisDebugMode?Log.w(tag,msg):-1;
}publicstaticinte(Stringtag,Stringmsg){returnisDebugMode?Log.e(tag,msg):-1;
}
}
默许是不开启日志打印,防止开发者忘掉设置。
一般日志和奔溃栈体系日志在操控台的输出比照
现在咱们在APP里边运用ZLog打印日志,代码为:
ZLog.setDebugMode(true);
ZLog.e(“ZLog”,”justtest”);
输出如下:
咱们现在增加如下代码:
StringnullString=null;if(nullString.equals(“null”)){
}
运转之后操控台会显现空指针反常奔溃栈,如下:
能够看到奔溃栈信息会显现详细是哪个文件呈现了空指针,以及详细哪一行。在咱们这个比如里边便是MainActivity.java的24行。
并且点击蓝色链接光标会直接定位到错误方位。
假如咱们一般的日志也能够点击就跳转到对应方位,关于咱们开发来说效率是有很大提高的。
ZLogHelper
已然奔溃栈里边有链接能够跳转,那么咱们能够经过栈信息来获取日志的打印方位。
咱们直接上代码:
publicclassZLogHelper{privatestaticfinalintCALL_STACK_INDEX=1;privatestaticfinalPatternANONYMOUS_CLASS=Pattern.compile(“(\\$\\d+)+$”);publicstaticStringwrapMessage(intstackIndex,Stringmessage){//DONOTswitchthistoThread.getCurrentThread().getStackTrace().if(stackIndex<0){
stackIndex=CALL_STACK_INDEX;
}
StackTraceElement[]stackTrace=newThrowable().getStackTrace();if(stackTrace.length<=stackIndex){thrownewIllegalStateException(“Syntheticstacktracedidn’thaveenoughelements:areyouusingproguard?”);
}
Stringclazz=extractClassName(stackTrace[stackIndex]);intlineNumber=stackTrace[stackIndex].getLineNumber();
message=”.(“+clazz+”.java:”+lineNumber+”)-“+message;returnmessage;
}/**
*Extracttheclassnamewithoutanyanonymousclasssuffixes(e.g.,{@codeFoo$1}
*becomes{@codeFoo}).
*/privatestaticStringextractClassName(StackTraceElementelement){
Stringtag=element.getClassName();
Matcherm=ANONYMOUS_CLASS.matcher(tag);if(m.find()){
tag=m.replaceAll(“”);
}returntag.substring(tag.lastIndexOf(‘.’)+1);
}
}
这儿咱们对外供给一个wrapMessage办法,看姓名就知道是对Message进行包装。
办法里边也是对StackTraceElement进行分析。
这边还做了一个操控,防止stackIndex呈现负数状况。
或许有小伙伴会好奇,为什么要把stackIndex对外开放呢?
因为你打印日志的当地不相同,这儿的stackIndex也需求对应调整。
办法里边是对StackTraceElement做处理,而StackTraceElement跟你的办法层级有联系。
咱们以最常用的两种日志打印方式为例,来阐明这儿的stackIndex要怎样传递,以及这个ZLogHelper的用法。
直接代码运用
咱们在MainActivity.java中直接运用,stackIndex传入1即可。
Log.e(“ZLog”,ZLogHelper.wrapMessage(1,”justtest”));
操控台输出如下:
能够看到代码地点的类和行数到显现为链接文本,点击会定位到详细的方位。
做了封装的状况
一般咱们对Log都会做封装,因而假定咱们有一个LogUtils类,咱们在MainActivity.java里边调用。
LogUtils.java:
classLogUtils{publicstaticvoidloge(){
Log.e(“ZLog”,ZLogHelper.wrapMessage(2,”justtest”));
}
}
MainActivity.java:
LogUtils.loge();
咱们先看下结果,再来分析。操控台输出如下:
能够看到的确定位到了MainActivity.java中的详细运用当地。
那么为什么这儿传入的stackIndex跟第一种不相同,是2而不是1呢?
其实答案很简单,你改为1之后,输出的操控台显现的会定位到LogUtils里边的日志打印句子处。在这儿便是:
Log.e(“ZLog”,ZLogHelper.wrapMessage(2,”justtest”));
所以其实你能够看出一个规则,而这个从代码也能够发现。
因为代码里边解析调用方位是根据栈来的,对StackTraceElement进行分析,因而状况一直接运用,传入1。而状况二多了一层函数调用,经过loge办法做了一层包装。因而需求传入2。假如你再套一层,那么需求传入3。了解了这一点,咱们下面的东西类信任你就看得懂了。
ZLog
假如你不想自己手动传入stackIndex,能够直接运用咱们供给的东西类ZLog。
publicclassZLog{privatestaticbooleanisDebugMode=false;publicstaticvoidsetDebugMode(booleandebugMode){
isDebugMode=debugMode;
}privatestaticbooleanisLinkMode=true;publicstaticvoidsetLinkMode(booleanlinkMode){
isLinkMode=linkMode;
}privatestaticfinalintCALL_STACK_INDEX=3;publicstaticintv(Stringtag,Stringmsg){returnisDebugMode?Log.v(tag,mapMsg(msg)):-1;
}publicstaticintd(Stringtag,Stringmsg){returnisDebugMode?Log.d(tag,mapMsg(msg)):-1;
}publicstaticinti(Stringtag,Stringmsg){returnisDebugMode?Log.i(tag,mapMsg(msg)):-1;
}publicstaticintw(Stringtag,Stringmsg){returnisDebugMode?Log.w(tag,mapMsg(msg)):-1;
}publicstaticinte(Stringtag,Stringmsg){returnisDebugMode?Log.e(tag,mapMsg(msg)):-1;
}privatestaticStringmapMsg(Stringmsg){returnisLinkMode?ZLogHelper.wrapMessage(CALL_STACK_INDEX,msg):msg;
}
}
信任有了前面的常识,小伙伴关于这儿为什么传入3应该了解了。
1的话会定位到
returnisLinkMode?ZLogHelper.wrapMessage(CALL_STACK_INDEX,msg):msg;
2的话(以e为例)会定位到
returnisDebugMode?Log.e(tag,mapMsg(msg)):-1;
3的话才能够定位到外面详细的调用途。
优化
咱们知道,虽然ZLog做了封装,但是咱们每次打日志都要传入ZLog,有点麻烦?
能否供给一个默许的TAG,允许对外设置。
能够的,咱们修改如下(以e为例):
privatestaticStringtag=”ZLOG”;publicstaticvoidsetTag(Stringtag){if(!TextUtils.isEmpty(tag)){
ZLog.tag=tag;
}
}publicstaticinte(Stringtag,Stringmsg){returnisDebugMode?Log.e(mapTag(tag),mapMsg(msg)):-1;
}publicstaticinte(Stringmsg){returnisDebugMode?Log.e(tag,mapMsg(msg)):-1;
}privatestaticStringmapTag(Stringtag){returnTextUtils.isEmpty(tag)?ZLog.tag:tag;
}
项目实战
按照下面两步引入开源库。
Step1.AddtheJitPackrepositorytoyourbuildfile
Additinyourrootbuild.gradleattheendofrepositories:
allprojects{
repositories{

maven{url’https://jitpack.io’}
}
}
Step2.Addthedependency
dependencies{
implementation’com.github.nesger:AndroidWheel:1.0.0′}
运用时先打开开关:
ZLog.setDebugMode(true);
然后就能够直接运用了。
温馨提示
由于带链接的debug对功能有必定影响,因而建议开发运用,上线关闭。
结语
这边在完善一个开源仓库AndroidWheel,跟姓名相同,防止重复造轮子。
现在1.0.0版本供给日志相关东西类,1.0.1增加了防抖动EditText。
后续会持续更新迭代,功能会更完善更全面。
觉得不错,欢迎给个star哈~

未经允许不得转载:IT技术网站 » Android Debug 之 Log 最佳实践
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载