目录
目标
1.对Log类做一个封装,取消tag参数,只保留msg信息
2.输出当前日志输出位置所在的类,方法和代码行号
1封装
从最简单的一步开始,对log.d()进行封装
public class LoggerUtils {
public static void d(String msg){
String clazz="className";
String method="methodName";
String line="lineNum";
StringBuilder sb=new StringBuilder();
sb.append(clazz)
.append(".")
.append(method)
.append(line);
Log.d(sb.toString(), msg);
}
}
2增加日志信息
在AS中,有调试工具,可以方便我们打断点,运行程序并查看断点位置的方法和值.这实际上是因为java虚拟机,会随时保存运行调用的方法和变量值到堆栈中,打断点的作用,相当于方便的插入了一个日志输出点
现在用代码来实现
参考并学习这里 浅谈getStackTrace()方法(一)
在java中运行代码
/**
* 用来测试堆栈信息
*/
public class StackTest {
private static void test(){
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
System.out.println("The stackTraceElements length:" + stackTraceElements.length);
for (int i = 0; i < stackTraceElements.length; i++) {
System.out.println("\n---the " + i + " element" + "---");
System.out.println("toString:" + stackTraceElements[i].toString());
System.out.println("ClassName:" + stackTraceElements[i].getClassName());
System.out.println("FileName:" + stackTraceElements[i].getFileName());
System.out.println("LineNumber:" + stackTraceElements[i].getLineNumber());
System.out.println("MethodName:" + stackTraceElements[i].getMethodName());
}
}
public static void main(String[] args) {
test();
}
}
获得以下输出
The stackTraceElements length:3
---the 0 element---
toString:java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
ClassName:java.lang.Thread
FileName:Thread.java
LineNumber:1606
MethodName:getStackTrace
---the 1 element---
toString:com.npt.stack_test.StackTest.test(StackTest.java:10)
ClassName:com.npt.stack_test.StackTest
FileName:StackTest.java
LineNumber:10
MethodName:test
---the 2 element---
toString:com.npt.stack_test.StackTest.main(StackTest.java:23)
ClassName:com.npt.stack_test.StackTest
FileName:StackTest.java
LineNumber:23
MethodName:main
Process finished with exit code 0
可以发现在stackTraceElements中,第一个方法必然是getStackTrace(),然后按照调用顺序,依次是test(),main()
stackTraceElements中还保存了调用方法所属的类名,以及在文件中的第几行的行号
在安卓应用中运行上面的代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
test();
}
private void test() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
System.out.println("The stackTraceElements length:" + stackTraceElements.length);
for (int i = 0; i < stackTraceElements.length; i++) {
System.out.println("\n---the " + i + " element" + "---");
System.out.println("toString:" + stackTraceElements[i].toString());
System.out.println("ClassName:" + stackTraceElements[i].getClassName());
System.out.println("FileName:" + stackTraceElements[i].getFileName());
System.out.println("LineNumber:" + stackTraceElements[i].getLineNumber());
System.out.println("MethodName:" + stackTraceElements[i].getMethodName());
}
}
}
查看logcat输出
System.out: The stackTraceElements length:17
System.out: ---the 0 element---
System.out: toString:dalvik.system.VMStack.getThreadStackTrace(Native Method)
System.out: ClassName:dalvik.system.VMStack
System.out: FileName:VMStack.java
System.out: LineNumber:-2
System.out: MethodName:getThreadStackTrace
System.out: ---the 1 element---
System.out: toString:java.lang.Thread.getStackTrace(Thread.java:580)
System.out: ClassName:java.lang.Thread
System.out: FileName:Thread.java
System.out: LineNumber:580
System.out: MethodName:getStackTrace
System.out: ---the 2 element---
System.out: toString:com.npt.testdemo.MainActivity.test(MainActivity.java:17)
System.out: ClassName:com.npt.testdemo.MainActivity
System.out: FileName:MainActivity.java
System.out: LineNumber:17
System.out: MethodName:test
System.out: ---the 3 element---
System.out: toString:com.npt.testdemo.MainActivity.onCreate(MainActivity.java:13)
System.out: ClassName:com.npt.testdemo.MainActivity
System.out: FileName:MainActivity.java
System.out: LineNumber:13
System.out: MethodName:onCreate
System.out: ---the 4 element---
System.out: toString:android.app.Activity.performCreate(Activity.java:6033)
System.out: ClassName:android.app.Activity
System.out: FileName:Activity.java
System.out: LineNumber:6033
System.out: MethodName:performCreate
System.out: ---the 5 element---
System.out: toString:android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
System.out: ClassName:android.app.Instrumentation
System.out: FileName:Instrumentation.java
System.out: LineNumber:1106
System.out: MethodName:callActivityOnCreate
System.out: ---the 6 element---
System.out: toString:android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
System.out: ClassName:android.app.ActivityThread
System.out: FileName:ActivityThread.java
System.out: LineNumber:2278
System.out: MethodName:performLaunchActivity
System.out: ---the 7 element---
System.out: toString:android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
System.out: ClassName:android.app.ActivityThread
System.out: FileName:ActivityThread.java
System.out: LineNumber:2387
System.out: MethodName:handleLaunchActivity
System.out: ---the 8 element---
System.out: toString:android.app.ActivityThread.access$800(ActivityThread.java:151)
System.out: ClassName:android.app.ActivityThread
System.out: FileName:ActivityThread.java
System.out: LineNumber:151
System.out: MethodName:access$800
System.out: ---the 9 element---
System.out: toString:android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
System.out: ClassName:android.app.ActivityThread$H
System.out: FileName:ActivityThread.java
System.out: LineNumber:1303
System.out: MethodName:handleMessage
System.out: ---the 10 element---
System.out: toString:android.os.Handler.dispatchMessage(Handler.java:102)
System.out: ClassName:android.os.Handler
System.out: FileName:Handler.java
System.out: LineNumber:102
System.out: MethodName:dispatchMessage
System.out: ---the 11 element---
System.out: toString:android.os.Looper.loop(Looper.java:135)
System.out: ClassName:android.os.Looper
System.out: FileName:Looper.java
System.out: LineNumber:135
System.out: MethodName:loop
System.out: ---the 12 element---
System.out: toString:android.app.ActivityThread.main(ActivityThread.java:5254)
System.out: ClassName:android.app.ActivityThread
System.out: FileName:ActivityThread.java
System.out: LineNumber:5254
System.out: MethodName:main
System.out: ---the 13 element---
System.out: toString:java.lang.reflect.Method.invoke(Native Method)
System.out: ClassName:java.lang.reflect.Method
System.out: FileName:Method.java
System.out: LineNumber:-2
System.out: MethodName:invoke
System.out: ---the 14 element---
System.out: toString:java.lang.reflect.Method.invoke(Method.java:372)
System.out: ClassName:java.lang.reflect.Method
System.out: FileName:Method.java
System.out: LineNumber:372
System.out: MethodName:invoke
System.out: ---the 15 element---
System.out: toString:com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
System.out: ClassName:com.android.internal.os.ZygoteInit$MethodAndArgsCaller
System.out: FileName:ZygoteInit.java
System.out: LineNumber:902
System.out: MethodName:run
System.out: ---the 16 element---
System.out: toString:com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
System.out: ClassName:com.android.internal.os.ZygoteInit
System.out: FileName:ZygoteInit.java
System.out: LineNumber:697
System.out: MethodName:main
可以看到安卓activity的调用是要经过非常多的步骤的.这里暂时打住,只关注我们的代码,test()
可以看到,与java类似,在stackTrace中,首先保存的是getStackTrace本身,不过由于android的虚拟机dalvik是对java虚拟机的优化,getStackTrace()方法实际上是还要调用getThreadStackTrace(Native Method),一个本地方法
test()方法在第三个,而test()所在的方法在第四个,onCreate(),行号13与我本地位置也对的上
那么在这里就可以继续对封装优化
public class LoggerUtils {
public static void d(String msg){
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
//获取日志所在方法的类
String clazz=stackTraceElements[3].getClassName();
//如果有一连串包名,只包留最后一个类名
String[] path=clazz.split("\\.");
if (path.length>0){
clazz=path[path.length-1];
}
//获取日志类所在的方法名
String method=stackTraceElements[3].getMethodName();
//获取日志在调用类中的代码行数
int line=stackTraceElements[3].getLineNumber();
//按照 [类名].[方法名](line:[行数])的格式拼接日志信息头
String sb = clazz +
"." +
method +
"(line:" +
line +
")";
//输出信息头+日志
Log.d(sb, msg);
}
}
然后尝试下应用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoggerUtils.d("Hello World!");
}
}
如愿以偿的看到输出
MainActivity.onCreate(line:13): Hello World!
git线上地址