Android KLog源代码分析
Android KLog源代码分析
一直使用这个库。但没有细致研究。今天就来研究一下。该库的地址:
KLog,在这里先感谢下作者。棒棒哒!
代码结构
整个代码的结构非常easy。例如以下:
library
klog
BaseLog.java
FileLog.java
JsonLog.java
XmlLog.java
KLog.java
KLogUtil.java
共六个文件:
- BaseLog.java,支持主要的log打印
- FileLog.java。支持以文件的形式保存log
- JsonLog.java,支持打印json对象和json数组
- XmlLog.java,支持打印Xml形式的log
详细分析
BaseLog
两个方法:
public class BaseLog {
private static final int MAX_LENGTH = 4000;
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) {// 超过指定长度,粉刺打印。这样就避免了系统默认的log长度限制了
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);
}
}
private static void printSub(int type, String tag, String sub) {
switch (type) {
case KLog.V:
Log.v(tag, sub);
break;
case KLog.D:
Log.d(tag, sub);
break;
case KLog.I:
Log.i(tag, sub);
break;
case KLog.W:
Log.w(tag, sub);
break;
case KLog.E:
Log.e(tag, sub);
break;
case KLog.A:
Log.wtf(tag, sub);
break;
}
}
}
这里突破了android系统的log字数限制,事实上就是超过字数限制后。採用分次打印的方法来打印,其它代码不做分析,比較简单。
FileLog
三个方法
public class FileLog {
private static final String FILE_PREFIX = "KLog_";
private static final String FILE_FORMAT = ".log";
/**
* @param tag log tag
* @param targetDirectory log file save dir
* @param fileName log file name
* @param headString log file 文件头
* @param msg log file log内容主体
*/
public static void printFile(String tag, File targetDirectory, @Nullable String fileName, String headString, String msg) {
fileName = (fileName == null) ? getFileName() : fileName;
if (save(targetDirectory, fileName, msg)) {
Log.d(tag, headString + " save log success ! location is >>>" + targetDirectory.getAbsolutePath() + "/" + fileName);
} else {
Log.e(tag, headString + "save log fails !");
}
}
/**
* @param dic log file save dir
* @param fileName og file name
* @param msg log file log内容主体
* @return true if save success
*/
private static boolean save(File dic, @NonNull String fileName, String msg) {
File file = new File(dic, fileName);
try {
OutputStream outputStream = new FileOutputStream(file);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");
outputStreamWriter.write(msg);
outputStreamWriter.flush();
outputStream.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 当未设置文件名称时,随机生成一个文件名称
*
* @return default file name
*/
private static String getFileName() {
Random random = new Random();
return FILE_PREFIX + Long.toString(System.currentTimeMillis() + random.nextInt(10000)).substring(4) + FILE_FORMAT;
}
}
JsonLog
JsonLog就更简单了,仅仅有一个方法(本宝宝曾经还以为Json打印会非常麻烦呢)
public class JsonLog {
public static void printJson(String tag, String msg, String headString) {
String message;
try {
if (msg.startsWith("{")) {// 处理json对象
JSONObject jsonObject = new JSONObject(msg);
message = jsonObject.toString(KLog.JSON_INDENT);
} else if (msg.startsWith("[")) {// 处理json数组
JSONArray jsonArray = new JSONArray(msg);
message = jsonArray.toString(KLog.JSON_INDENT);
} else {
message = msg;
}
} catch (JSONException e) {
message = msg;
}
KLogUtil.printLine(tag, true);// 调用格式化方法
message = headString + KLog.LINE_SEPARATOR + message;
String[] lines = message.split(KLog.LINE_SEPARATOR);
for (String line : lines) {
Log.d(tag, "║ " + line);
}
KLogUtil.printLine(tag, false);// 调用格式化方法
}
}
XmlLog
两个方法:
public class XmlLog {
/**
* 打印xml
*
* @param tag log tag
* @param xml xml content
* @param headString 文件头
*/
public static void printXml(String tag, String xml, String headString) {
if (xml != null) {
xml = XmlLog.formatXML(xml);
xml = headString + "\n" + xml;
} else {
xml = headString + KLog.NULL_TIPS;
}
KLogUtil.printLine(tag, true);
String[] lines = xml.split(KLog.LINE_SEPARATOR);
for (String line : lines) {
if (!KLogUtil.isEmpty(line)) {
Log.d(tag, "║ " + line);
}
}
KLogUtil.printLine(tag, false);
}
/**
* @param inputXML xml content
* @return 格式化后的xml String
*/
private static String formatXML(String inputXML) {
try {
Source xmlInput = new StreamSource(new StringReader(inputXML));
StreamResult xmlOutput = new StreamResult(new StringWriter());
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(xmlInput, xmlOutput);
return xmlOutput.getWriter().toString().replaceFirst(">", ">\n");
} catch (Exception e) {
e.printStackTrace();
return inputXML;
}
}
}
细心的你会发现。不管是Json形式还是XML形式。调用的都是系统原生的方法来处理数据,因此又时候对熟悉熟悉java(或android)提供的方法还是非常方便的。哈哈。
上面用到的KLogUtil,例如以下:
public class KLogUtil {
public static boolean isEmpty(String line) {
return TextUtils.isEmpty(line) || line.equals("\n") || line.equals("\t") || TextUtils.isEmpty(line.trim());
}
public static void printLine(String tag, boolean isTop) {
if (isTop) {
Log.d(tag, "╔═══════════════════════════════════════════════════════════════════════════════════════");
} else {
Log.d(tag, "╚═══════════════════════════════════════════════════════════════════════════════════════");
}
}
}
核心文件KLog.java分析
给方法主要提供了相似于系统log方法的不同重载,比較简单,我这里要讲的是那个获取log详细有关的类名、方法名、行号等。与之相关的就是wrapperContent这种方法了。
private static String[] wrapperContent(int stackTraceIndex, String tagStr, Object... objects) {
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;
}
String tag = (tagStr == null ? className : tagStr);
if (mIsGlobalTagEmpty && TextUtils.isEmpty(tag)) {
tag = TAG_DEFAULT;
} else if (!mIsGlobalTagEmpty) {
tag = mGlobalTag;
}
// 得到消息主体
String msg = (objects == null) ? NULL_TIPS : getObjectsString(objects);
String headString = "[ (" + className + ":" + lineNumber + ")#" + methodName + " ] ";
return new String[]{tag, msg, headString};
}
/**
* 得到消息主体
*
* @param objects 消息对象数组
* @return 消息主体字符串
*/
private static String getObjectsString(Object... objects) {
if (objects.length > 1) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("\n");
for (int i = 0; i < objects.length; i++) {
Object object = objects[i];
if (object == null) {
stringBuilder.append(PARAM).append("[").append(i).append("]").append(" = ").append(NULL).append("\n");
} else {
stringBuilder.append(PARAM).append("[").append(i).append("]").append(" = ").append(object.toString()).append("\n");
}
}
return stringBuilder.toString();
} else {
Object object = objects[0];
return object == null ?
NULL : object.toString();
}
}
分析完成,是不是非常easy,假设你看了这个库的代码。你会认为我的分析都是多余的。
遇到的问题
在使用KLog打印json形式信息时。假设网络请求时异步的,会导致KLog.json打印的格式出现错乱。即一个结果还没有全然打印出来。里外一个就開始打印了,这个应该是并发导致的问题,之后我会在KLog的基础上对这个问题进行优化的。
Android KLog源代码分析的更多相关文章
- Android 消息处理源代码分析(1)
Android 消息处理源代码分析(1) 在Android中,通常被使用的消息队列的代码在文件夹\sources\android-22\android\os下,涉及到下面几个类文件 Handler.j ...
- Android HandlerThread 源代码分析
HandlerThread 简单介绍: 我们知道Thread线程是一次性消费品,当Thread线程运行完一个耗时的任务之后.线程就会被自己主动销毁了.假设此时我又有一 个耗时任务须要运行,我们不得不又 ...
- Android HttpURLConnection源代码分析
Android HttpURLConnection源代码分析 之前写过HttpURLConnection与HttpClient的差别及选择.后来又分析了Volley的源代码. 近期又遇到了问题,想在V ...
- android开发源代码分析--多个activity调用多个jni库的方法
android开发源代码分析--多个activity调用多个jni库的方法 有时候,我们在开发android项目时会遇到须要调用多个native c/jni库文件,下面是本人以前实现过的方法,假设有知 ...
- Android 消息处理源代码分析(2)
Android 消息处理源代码分析(1)点击打开链接 继续接着分析剩下的类文件 Looper.java public final class Looper { final MessageQueue m ...
- Appium Android Bootstrap源代码分析之启动执行
通过前面的两篇文章<Appium Android Bootstrap源代码分析之控件AndroidElement>和<Appium Android Bootstrap源代码分析之命令 ...
- Android AsyncTask 源代码分析
AsyncTask源代码分析 public abstract class AsyncTask<Params, Progress, Result> { //日志TAG private sta ...
- Appium Android Bootstrap源代码分析之简单介绍
在上一个系列中我们分析了UiAutomator的核心源代码,对UiAutomator是怎么执行的原理有了根本的了解.今天我们会開始另外一个在安卓平台上基于UiAutomator的新起之秀--Appiu ...
- [Android] Volley源代码分析(五岁以下儿童)Q \\ u0026一个
Volley源代码分析系列那里一段时间,告诉我,有许多私人留言,同时一些问题抛出.对于一些简单的问题,我们跳,这两天被连接到朋友@smali提出的问题.告诉我你不得不赞叹查看源代码时的详细程度,大家一 ...
随机推荐
- C#.NET常见问题(FAQ)-控制台程序如何做弹窗
最简单的弹窗,只要引用System.Windows.Forms,就可以使用WinForm的弹窗 如果要弹出是/否的选择对话框,则可以拷贝下面的代码 DialogResult dr = Messag ...
- C118+OSMCOMBB嗅探短信
ubuntu系统:12.04.4, 下载地址:http://cdimage.ubuntu.com/releases/12.04.4/release/ 编译环境下载 : http://pan.baidu ...
- 【转】跟我一起学Spring 3(4)–深入理解IoC(控制反转)和DI(依赖注入)
在继续下面的章节之前,我们要先说说大名鼎鼎的IoC和DI. 我们经常会听说IoC,也就是Inversion of Controller,控制反转.事实上,IoC并不是一个新鲜的概念,最早可能是在198 ...
- Node,Sockets,Cores,Threads
http://fishcried.com/2015-01-09/cpu_topology/ http://kodango.com/cpu-topology http://www.udpwork.com ...
- CSS知识点集锦
CSS知识点集锦 CreateTime--2016年9月29日09:43:10Author:Marydon UpdateTime--2017年3月21日08:03:13 2.CSS样式优先级问题 ...
- PHP5.4 需要添加的configure参数
./configure --prefix=/usr/local/php --with-gd=/usr/local/gd --with-jpeg-dir=/usr/local/jpeg --with-p ...
- centos6.5关闭ipv6
万境归空,道法自然 1.在/etc/modprobe.d/目录下增加一个新的配置文件ipv6.conf cat << EOF > /etc/modprobe.d/ipv6.confa ...
- 转: 在Ogre中使用Havok物理引擎(源码)
作者:CYM 众所周知Ogre则是评价很高的一款图形渲染引擎,Havok则是世界一流的物理引擎,今天花了点时间将两者结合在了一块,做了个Demo 由于国内对Havok的研究似乎很少,网上也找不到多少资 ...
- EntityFramework 5.0 CodeFirst 教程03-数据结构的定义/列的属性
---------------------目录-------------------------- EntityFramework 5.0 CodeFirst 教程03-数据结构的定义/列的属性 (2 ...
- 怎样查看SSL证书的有效期?自动续期是否生效?
前面一篇教程教大家如何能够把网站的 HTTPS 的 SSL 证书自动续期.料神米课的学员动手能力都很强,已经很多都成功把证书续期了.但怎么看证书续期是否成功了呢? 使用火狐 firefox 浏览器就可 ...