在Android Studio查看错误日志的时候,出错位置的代码前会出现链接,点击就会跳到源代码的位置,非常方便。但是我们平常使用的Log.x()方法打印出的日志却只能打印出简单的内容,如果内容一多,那么查看日志的时候就会非常乱,分不清哪行日志是在哪里打印出来的了。
所以就想到也可以仿照系统打印错误日志的方式打印我们自己的代码。点击一行日志,就能跳到对应的源代码位置。这里我们需要借助JDK自带的StackTraceElement类,可以用来获取方法的调用栈信息。
protected String getNameFromTrace(StackTraceElement[] traceElements, int place) {
StringBuilder taskName = new StringBuilder();
if (traceElements != null && traceElements.length > place) {
StackTraceElement traceElement = traceElements[place];
taskName.append(traceElement.getMethodName());
taskName.append("(").append(traceElement.getFileName()).append(":").append(traceElement.getLineNumber()).append(")");
}
return taskName.toString();
}
private String getContent(String msg, int place,Object... args) {
try {
String sourceLinks = getNameFromTrace(Thread.currentThread().getStackTrace(), place);
return sourceLinks + String.format(msg, args);
} catch (Throwable throwable) {
return msg;
}
}
因为Thread.currentThread().getStackTrace()得到的是一个数组,里面各个位置StackTraceElement保存的信息也不一样。所以我们可以简单循环,打印出每个对象出来。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
printD("MyTag:", "xxxxx");
}
public void printD(String tag, String content, Object... args) {
for (int i = 0; i < Thread.currentThread().getStackTrace().length; i++) {
String realContent = getContent(content,i,args);
Log.d(tag, realContent);
}
}
image.png
可以看到,前两个是VM和Thread的方法,第三个开始才是我们自己写的方法,因为我做了两次调用,所以出现了三个方法带链接,而第五个正式我们最初调用的代码位置,即place=4。如果间接调用的层次更多,那么位置也更靠后面。
最后我简单封装了下这个Log工具类,即可打印出点击跳到原位置的log。
public class LogUtils {
public static void PrintD(String content, Object... args) {
for (int i = 0; i < Thread.currentThread().getStackTrace().length; i++) {
String realContent = getContent(content, i, args);
Log.d("default", realContent);
}
}
public static void PrintD(String tag, String content, Object... args) {
Log.d(tag, getContent(content, 4, args));
}
private static String getNameFromTrace(StackTraceElement[] traceElements, int place) {
StringBuilder taskName = new StringBuilder();
if (traceElements != null && traceElements.length > place) {
StackTraceElement traceElement = traceElements[place];
taskName.append(traceElement.getMethodName());
taskName.append("(").append(traceElement.getFileName()).append(":").append(traceElement.getLineNumber()).append(")");
}
return taskName.toString();
}
private static String getContent(String msg, int place, Object... args) {
try {
String sourceLinks = getNameFromTrace(Thread.currentThread().getStackTrace(), place);
return sourceLinks + String.format(msg, args);
} catch (Throwable throwable) {
return msg;
}
}
}