项目地址 https://github.com/xsfelvis/ZeusLog
主要分为两大块,移动端Log和控制台Log,先上图
主要支持
具体如下
【黄色区域】 当前Actvity名称
【红色区域】 log日志开启或者关闭,关闭后右边控制区域也随之消失,只有当前的Activity名称,如下
【橙色区域】 网络请求格式化显示区域,该部分透传所有点击事件,从而使整个App使用不受影响
【绿色区域】 自定义sideBar,滑动该区域控制橙色区域长文本滚动阅读
技术点:
没有采用window去实现,原因很简单,兼容性不好,现在各大厂商对自己的windows权限管理都很紧,而且正好尝试一下自定义view+事件分发,有了想法,一时技痒,就撸一个呗,当然你也可以有其他更好的思路,也可以跟我交流。
主要采用了自定义viewgroup+自定义view
SideDragBar
【绿色部分】,通过橙色部分显示内容,透传点击事件从而不影响用户对app操作,SideDragBar
控制内容区域的滚动,从而不影响内容区长文本的阅读。
几个关键点:
获取屏幕的content区域内容,然后将我们的自定义viewgroup add进去
ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
首先我们需要知道android中window的位置,下面摘了一张图
我们希望屏幕日志只是给用户用来查看,而不要影响用户对app的操作,但是也要对长文本支持,这样采用重写ScrollView包裹一个textView的方法来解决这个问题,这个ScrollView的拦截事件方法均被重写
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
这样这个scrollview就可以透传了,
"@+id/svContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="9">
"@color/white"
android:id="@+id/tvShowInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="日志显示 \n"
android:textSize="12dp"/>
这里思考了一会,最后给出的解决方案就是在边栏加一个自定义view SideDragBar【绿色部分】
通过重写dispatchTouchEvent
,记录滑动变化,然后使用控制传入的scrollview滚动
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction();
//记录当前点击位置
int x = (int) event.getX();
int y = (int) event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
case MotionEvent.ACTION_MOVE:
int offsetX = x-lastX;
int offsetY = y-lastY;
sv.smoothScrollBy(0,offsetY);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
总之就是通过重写scrollview使得控制滚动,从而解决这个问题
4.格式化json数据
关于这个,刚开始在网上找了一下,很多都是直接for循环一个一个字符的去解析,感觉实在不够优雅,而且效率也很低,其实JSONObject
、JSONArray
就可以解决这个问题
String message;
try{
if(msg.startsWith("{")){
JSONObject jsonObject = new JSONObject(msg);
message = jsonObject.toString(ZeusLog.JSON_INDENT);
}else if(msg.startsWith("[")){
JSONArray jsonArray = new JSONArray(msg);
message = jsonArray.toString(ZeusLog.JSON_INDENT);
}else {
message = msg;
}
}catch (JSONException e){
message = msg;
}
控制台有一些比较全的Log库,如orhanobut/logger、JakeWharton/timber等,感觉这些库写的都很重,当然功能很全,个人不太不喜欢他们打印log格式化方式,而且也想看看具体原理还有也不想增加无需求的功能,如xml格式化等,最终自己搓了一个支持基本log+多参数+json格式,具体如下:
基本tag
无tag显示当前类名
格式化输出json
多参数log
几个关键点
这个需要使用到Thread.currentThread().getStackTrace()
返回的是一个StackTraceElement数组,内容为调用函数堆栈,并且以调用层级关系保存。android中对应返回值数组是19个,而且最终都是调用
dalvik.system.NativeStart.main(Native Method)
有兴趣的可以断点看下,其实日志打印工具类实现都离不开它的应用,然后获取对应index的StackTraceElement你就可以获取当前行号,类名,部分代码如下
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
StackTraceElement targetElement = stackTrace[stackTraceIndex];
String className = targetElement.getClassName();
String[] classNameInfo = className.split("\\.");
if (classNameInfo.length > 0) {
className = classNameInfo[classNameInfo.length - 1] + SUFFIX;
}
if (className.contains("$")) {
className = className.split("\\$")[0] + SUFFIX;
}
String methodName = targetElement.getMethodName();
int lineNumber = targetElement.getLineNumber();
if (lineNumber < 0) {
lineNumber = 0;
}
先介绍下Android中Log的实现结构
可以看出大致过程 App通过util.log.产生日志->JVM->JNI(Native C)调用->log_write的sys_call()->logger驱动->dispatch分发给订阅者,android打印受限问题就出在这个Logger驱动上
#define LOGGER_ENTRY_MAX_LEN (4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD \\
(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
可以看出,系统的显示单条Log长度是有限制的4*1024字符长度,那么我们打印日志的时候可以对症下药,在写自己的log日志时可以对msg做下处理,采取分段打印
public static void printDefault(int type, String tag, String msg) {
int index = 0;
int length = msg.length();
int countOfSub = length / MAX_LENGTH;
if (countOfSub > 0) {
for (int i = 0; i < countOfSub; i++) {
String sub = msg.substring(index, index + MAX_LENGTH);
printSub(type, tag, sub);
index += MAX_LENGTH;
}
printSub(type, tag, msg.substring(index, length));
} else {
printSub(type, tag, msg);
}
}
compile 'com.xsf:zeusLog:1.0.0'
移动端Log使用很简单,需要在你想打印的地方,调用如下API即可
ZeusMobileView.startZeus(MainActivity.this).setJsonStr(JSON_LONG);
控制台Log 需要先初始化安全等级
ZeusLog.init(BuildConfig.DEBUG);
表示仅仅在debug包下打印日志,如果不初始化也可使用,但是需要注意release包保护
然后如同使用系统API一样使用即可
不带tag
带tag
json格式化
多个参数
最后感谢你宝贵的时间阅读,如果你喜欢的话可以点赞收藏,也可以关注我的账号,大家一起交流技术。