Android可跳轉指定位置的Log

在使用Android Studio開發的時候,當程序出現錯誤的時候,我們通常可以通過點擊錯誤日誌跳轉到指定方法出錯的那一行。例如,下圖便是常見的空指針異常所拋出的錯誤日誌:
這裏寫圖片描述

然而,當我們自己使用Log.x去打印Log的時候卻沒有這種跳轉的功能,只能顯示打印的信息。那麼如何實現讓我們打印的日誌也能跳轉呢?其實方法很簡單,只要讓我們打印的日誌信息符合系統的要求,你輸出的日誌信息就會自動實現可跳轉的功能。所以只要讓你的輸出的日誌符合這種要求便可。這裏,我們可以使用JDK自帶的StackTraceElement類來幫助我們實現這種要求,StackTraceElement可以簡單理解爲是記錄調用棧信息的類,也就是說,我們的輸出信息含有了這種調用棧信息,便可以實現自動跳轉的功能。

下面給出兩個種實現方法:

  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();
    //判斷調用棧的層級,大於place的纔打印Log輸出
    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;
    }
}
}

//在下面調用
  @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    printD("MyTag:", "xxxxx");

}



private StackTraceElement getTargetStackTraceElement() {
    // find the target invoked method
    StackTraceElement targetStackTrace = null;
    boolean shouldTrace = false;
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    for (StackTraceElement stackTraceElement : stackTrace) {
    //通過判斷是否屬於該類,來進行過濾掉無用的信息
        boolean isLogMethod = stackTraceElement.getClassName().equals(L.class.getName());
        if (shouldTrace && !isLogMethod) {
            targetStackTrace = stackTraceElement;
            break;
        }
        shouldTrace = isLogMethod;
    }
    return targetStackTrace;
}

public static void e(String tag, String msg, Object... params) {
    if (!sDebug) return;

    String finalTag = getFinalTag(tag);
    StackTraceElement targetStackTraceElement = getTargetStackTraceElement();
    Log.e(finalTag, "(" + targetStackTraceElement.getFileName() + ":"
            + targetStackTraceElement.getLineNumber() + ")");
    Log.e(finalTag, String.format(msg, params));
}

//在下面調用
public class L{
    private static boolean sDebug = true;
    private static String sTag = "zhy";

    public static void init(boolean debug, String tag){
        L.sDebug = debug;
        L.sTag = tag;
    }

    public static void e(String msg, Object... params){
        e(null, msg, params);
    }

    public static void e(String tag, String msg, Object[] params){
        if (!sDebug) return;
        tag = getFinalTag(tag);
        //TODO 通過stackElement打印具體log執行的行數
        Log.e(tag, content);
    }

    private static String getFinalTag(String tag){
        if (!TextUtils.isEmpty(tag)){
            return tag;
        }
        return sTag;
    }
}

上面兩種實現方法都是使用了 StackTraceElement類,主要區別在於:如何過濾掉無用信息。在下圖中,是一些沒有進行過濾的調用棧信息,而我們只需要藍色部分字體所在行的信息。所以,怎樣去掉其他行顯得很重要,上面則是兩種實現方法。
這裏寫圖片描述

第一種方法中,使用 if (traceElements != null && traceElements.length > place) ,通過調用層級place進行判斷,因爲處於低層的信息肯定是系統打印的信息(如上圖中的getThreadStackTrace(VMStack java-2)),這個肯定不是我們想看到的。所以,只要控制好層級數並可以過濾掉掉這些無用的信息。上文中代碼選用的層級爲4。具體根據自己的實現進行更改(即上面的LogUtils是怎樣實現的 )。

第二種方法是,通過stackTraceElement.getClassName().equals(L.class.getName()),即打印的信息是否是Log方法的調用方打印出來的,如上面的L類。在L類中調用打印Log,所以我們也只關心L類中輸出的信息,而不去關心其他基類的信息。於是,通過判斷類名是否爲L類也可過濾掉無用信息。

上述兩種方法均可實現過濾的效果,可以根據自身喜好進行選擇。

參考文章:

Android打印日誌,實現快速定位源代碼 ——大頭呆

Android 從StackTraceElement反觀Log庫 —— 鴻洋_

發佈了150 篇原創文章 · 獲贊 138 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章