最近在做一个日志工具类接触到StackTraceElement这个类 作用是获取当前调用的包括方法的类名、方法名、文件名以及调用的行数。
获取StackTraceElement的方法有两种,均返回StackTraceElement数组,也就是这个栈的信息。
1、Thread.currentThread().getStackTrace()
2、new Throwable().getStackTrace()
这个类可以帮助我们分析整个调用的流程 因为他会打印当前栈中的信息
StackTraceElement[] element = Thread.currentThread().getStackTrace();
for (int i = 0 ;i < element.length; i++){
Log.i(TAG, "getStackTraceElement: "+i+"\n"+element[i]);
}
以下是打印的栈信息:
getStackTraceElement: 0
dalvik.system.VMStack.getThreadStackTrace(Native Method)
getStackTraceElement: 1
java.lang.Thread.getStackTrace(Thread.java:1566)
getStackTraceElement: 2
robin.com.example.mybase.LogUtils.getStackTraceElement(LogUtils.java:136)
getStackTraceElement: 3
robin.com.example.mybase.LogUtils.getCallerStackLogTag(LogUtils.java:149)
getStackTraceElement: 4
robin.com.example.mybase.LogUtils.i(LogUtils.java:212)
getStackTraceElement: 5
robin.com.example.androidfoundation.MainActivity.onCreate(MainActivity.java:43)
getStackTraceElement: 6
android.app.Activity.performCreate(Activity.java:6765)
getStackTraceElement: 7
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1122)
getStackTraceElement: 8
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2829)
getStackTraceElement: 9
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2941)
getStackTraceElement: 10
android.app.ActivityThread.-wrap12(ActivityThread.java)
getStackTraceElement: 11
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1645)
getStackTraceElement: 12
android.os.Handler.dispatchMessage(Handler.java:110)
....
可以看到我们整个方法的调用过程,底部的最先开始调用,数组下标为5元素是我们调用的函数位置 所以我们可以直接返回这个下标的内容截取响应字段来打印调用位置相关信息比如:
String callerClazzName = element[5].getClassName();
callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
tag = String.format( "%s.%s(L:%d)" ,new Object[] { callerClazzName, caller.getMethodName(),Integer.valueOf(caller.getLineNumber()) });
其次还可以帮助我们确认某些方法是否在特定位置调用 比如一些SDK,会强制要求在某些方法中执行某个方法,例如,必须在Activity.onResume中执行,PVSdk.onResume,如果你之前遇到过某个SDK给你抛了类似的异常,那么它的原理就是这么实现的。
以下代码来自鸿洋博客
public class PVSdk {
public static void onResume() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
boolean result = false;
for (StackTraceElement stackTraceElement : stackTrace) {
String methodName = stackTraceElement.getMethodName();
String className = stackTraceElement.getClassName();
try {
boolean assignableFromClass = Class.forName(className).isAssignableFrom(Activity.class);
if (assignableFromClass && "onResume".equals(methodName)) {
result = true;
break;
}
} catch (ClassNotFoundException e) {
// ignored
}
}
if (!result)
throw new RuntimeException("PVSdk.onResume must in Activity.onResume");
//do other things
}
}
---------------------
作者:鸿洋_
来源:CSDN
原文:https://blog.csdn.net/lmj623565791/article/details/52506545
有了这个类我们就可以在日志中打印调用所在的类 、函数以及行数等信息,这样可以帮助我们快速定位问题
最后简单贴下日志工具类的主要方法:
先提供几个set函数用于设置是否显示log、设置tag、日志级别等
public static void setShowLog(boolean isShowLog) {
LogUtils.isShowLog = isShowLog;
}
public static void setTag(String tag) {
LogUtils.TAG=tag;
}
public static void setPriority(int priority) {
LogUtils.priority = priority;
}
/**
* 根据堆栈生成TAG
* @return TAG|className.methodName(L:lineNumber)
*/
private static String generateTag(StackTraceElement caller) {
String tag = TAG_FORMAT;
String callerClazzName = caller.getClassName();
callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
tag = String.format("%s.%s(L:%d)",new Object[] { callerClazzName, caller.getMethodName(),Integer.valueOf(caller.getLineNumber()) });
return new StringBuilder().append(TAG).append(VERTICAL).append(tag).toString();
}
最后是日志打印
public static void i(String msg) {
if (isShowLog && priority <= INFO)
Log.i(generateTag(getStackTraceElement(5)), String.valueOf(msg));
}
这样就完成了一个简单的日志工具类 当然自己还可以加入一些其他的东西 比如日志展示的样式