原文链接: http://blog.csdn.net/argel_lj/article/details/49925657
StackTrace(堆栈轨迹) 其中包含的消息 , 其实就是我们跑程序的时候报错 的相关消息。
本文简要介绍了StackTrace(堆栈轨迹)以及StackTraceElement的一些用法
一、什么是StackTrace
StackTrace(堆栈轨迹)可以认为是一系列方法调用过程的集合。
异常处理中常用的printStackTrace()即为打印异常调用的堆栈信息。
二、StackTraceElement介绍
StackTraceElement表示StackTrace(堆栈轨迹)中的一个元素,属性包括方法调用者的类名、方法名、文件名以及调用的行数。
- public final class StackTraceElement implements java.io.Serializable {
-
- private String declaringClass;
- private String methodName;
- private String fileName;
- private int lineNumber;
StackTraceElement被定义为final,可见其作为一个Java的基础类不允许被继承。
获取StackTraceElement的方法有两种,均返回StackTraceElement数组
1、Thread.currentThread().getStackTrace()
2、new Throwable().getStackTrace()
StackTraceElement数组包含了StackTrace(堆栈轨迹)的内容,通过遍历它可以得到方法间的调用过程,
即可以得到当前方法以及其调用者的方法名、调用行数等信息
- public class TestClass
- {
- public static void main(String[] args)
- {
- new TestClass().methodA();
- }
-
- private void methodA(){
- System.out.println("------进入methodA----------");
- methodB();
- }
-
- private void methodB(){
- System.out.println("------进入methodB----------");
- StackTraceElement elements[] = Thread.currentThread().getStackTrace();
- for (int i = 0; i < elements.length; i++) {
- StackTraceElement stackTraceElement=elements[i];
- String className=stackTraceElement.getClassName();
- String methodName=stackTraceElement.getMethodName();
- String fileName=stackTraceElement.getFileName();
- int lineNumber=stackTraceElement.getLineNumber();
- System.out.println("StackTraceElement数组下标 i="+i+",fileName="
- +fileName+",className="+className+",methodName="+methodName+",lineNumber="+lineNumber);
- }
- }
- }
执行main方法,输出信息如下
可以看到在方法B中使用getStackTrace,
得到StackTraceElement数组中下标为2的element表示方法B的调用者方法A的详细信息
三、用途
1、我们可以封装一个日志库,在打印目标日志的时候,也可以通过这个调用栈打印出这个日志所在的行数,这样就可以迅速的定位到日志输出行,再也不要全局搜索去查找了。
public static void d(String tag, String msg, Object... params) {
StackTraceElement targetStackTraceElement = getTargetStackTraceElement();
Log.d(tag, "(" + targetStackTraceElement.getFileName() + ":"
+ targetStackTraceElement.getLineNumber() + ")");
Log.d(tag, String.format(msg, params));
}
2、如果我们写了一个SDK,希望某个方法在固定的位置被调用,我们也可以在这个方法被调用的时候,进行检查,看这个方法的调用位置是否正确。
例如,必须在Activity.onResume中执行,PVSdk.onResume,所以我们在调用PVSdk.onResume方法的时候,在PVSdk.onResume方法里面来通过获取调用栈的信息检测这个方法是否在Activity的onResume方法中调用的。
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) {
}
}
if (!result)
throw new RuntimeException("PVSdk.onResume must in Activity.onResume");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
3、我们在进行源码分析的时候,如果想分析整个代码的执行流程,我们可以进行通过打印栈的信息来获取,这个在源码分析的时候还是挺有用的。