Android log的常见问题和常用方法

最近在总结了以下log的常见问题和常用方法,由于网络上的log框架太多,看了几个热门的也选择不了自己喜欢的,那就从中分析实用代码,从而实用到自己的工程中。

如何自动获取tag-即类名

public class LogTest {
    public String getTag() {
        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
        int traceOffset = getStackOffset(trace);
        String tagClassName = trace[traceOffset].getClassName();
        return getSimpleClassName(tagClassName);
    }

    private int getStackOffset(StackTraceElement[] trace) {
        int traceOffset = 3; // 0为VMStack,1为Thread,2为本类,固至少从3开始
        for (int i = traceOffset; i < trace.length; i++) {
            StackTraceElement e = trace[i];
            String name = e.getClassName();
            if (name.equals(LogTest.class.getName())) {
                // 打到自己类,得知调用本方法的类栈,从而得知要输出的tag的类
                traceOffset = i;
                break;
            }
        }
        return traceOffset;
    }

    private String getSimpleClassName(String name) {
        int lastIndex = name.lastIndexOf(".");
        return name.substring(lastIndex + 1).split("\\$")[0];
    }
}
Log.i("cyy", LogTest.getTag());  // 执行
I/cyy: SplashActivity// 输出,SplashActivity就是执行上一行代码的类

如何打印线程和调用位置

public class LogTest {

    public String getThreadInfo(){
        return Thread.currentThread().getName(); // 获取当前线程名
    }


    public String showMethod(int methodCount){
        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
        int traceOffset = getStackOffset(trace);
            StringBuilder builder = new StringBuilder();

        // 获取当前有效栈,并倒序输出执行行的信息
        for (int i = methodCount; i > 0; i--) {
            int stackIndex = i + traceOffset - 1;
            builder.append(getSimpleClassName(trace[stackIndex].getClassName())).append(".")
                    .append(trace[stackIndex].getMethodName()).append(" ").append(" (")
                    .append(trace[stackIndex].getFileName()).append(":").append(trace[stackIndex].getLineNumber())
                    .append(")");
            builder .append("\n");
        }
        return  builder.toString();
    }

    private int getStackOffset(StackTraceElement[] trace) {
        int traceOffset = 3; // 0为VMStack,1为Thread,2为本类,固至少从3开始
        for (int i = traceOffset; i < trace.length; i++) {
            StackTraceElement e = trace[i];
            String name = e.getClassName();
            if (name.equals(LogTest.class.getName())) {
                // 打到自己类,得知调用本方法的类栈,从而得知要输出的tag的类
                traceOffset = i;
                break;
            }
        }
        return traceOffset;
    }

    private String getSimpleClassName(String name) {
        int lastIndex = name.lastIndexOf(".");
        return name.substring(lastIndex + 1).split("\\$")[0];
    }

}

执行代码和结果:
这里写图片描述

如何打印异常

来自系统自带的Log类静态方法getStackTraceString。

    public static String getStackTraceString(Throwable tr) {
        if (tr == null) {
            return "";
        }

        Throwable t = tr;
        while (t != null) {
            if (t instanceof UnknownHostException) {
                return "";
            }
            t = t.getCause();
        }

        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        tr.printStackTrace(pw);
        pw.flush();
        return sw.toString();
    }

如何打印JSON

    public String json(String json) {
        int JSON_INDENT = 2; // 格式
        if (TextUtils.isEmpty(json)) {
            return "Empty - json";
        }
        try {
            json = json.trim();
            if (json.startsWith("{")) {
                JSONObject jsonObject = new JSONObject(json);
                return jsonObject.toString(JSON_INDENT);
            }
            if (json.startsWith("[")) {
                JSONArray jsonArray = new JSONArray(json);
                return jsonArray.toString(JSON_INDENT);
            }
            return "Invalid Json";
        } catch (JSONException e) {
            return Log.getStackTraceString(e);
        }
    }

如何打印xml

    public String xml(String xml) {

        if (TextUtils.isEmpty(xml)) {
            return "Empty - xml";
        }
        try {
            Source xmlInput = new StreamSource(new StringReader(xml));
            StreamResult xmlOutput = new StreamResult(new StringWriter());
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            transformer.transform(xmlInput, xmlOutput);
            return xmlOutput.getWriter().toString().replaceFirst(">", ">\n");
        } catch (TransformerException e) {
            return Log.getStackTraceString(e);
        }
    }

如何打印对象 (包含集合及数组)

如何依赖其他库,如gson打印对象就容易多了:

    public static String toJson(Object cls) {
        if (null == cls) {
            return "";
        }
        String obj = new Gson().toJson(cls);
        return obj;
    }

如果没有就通过反射的方式(支付打印集合,数组,Bundle)
先看效果:
这里写图片描述

import android.content.Intent;
import android.os.Bundle;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class LogTest {
    public final String BR = System.getProperty("line.separator");

    public String objectToString(Object object) {
        return objectToString(object, 0);
    }


    public String objectToString(Object object, int childLevel) {
        if (object == null) {
            return "Object[object is null]";
        }
        if (childLevel > 2) {
            return object.toString();
        }
        if (Map.class.isAssignableFrom(object.getClass())) {
            return parseMap((Map) object);
        } else if (Bundle.class.isAssignableFrom(object.getClass())) {
            return parseBundle((Bundle) object);
        } else if (Collection.class.isAssignableFrom(object.getClass())) {
            return parseCollection((Collection) object);
        } else if (object.getClass().isArray()) { // 数组
            return parseArray(object);
        }

        if (object.toString().startsWith(object.getClass().getName() + "@")) {
            StringBuilder builder = new StringBuilder();
            getClassFields(object.getClass(), builder, object, false, childLevel);
            Class superClass = object.getClass().getSuperclass();
            int i = 0;
            while (!superClass.equals(Object.class)) {
                i++;
                getClassFields(superClass, builder, object, true, childLevel);
                superClass = superClass.getSuperclass();
                if (i > 5) break;
            }
            return builder.toString();
        }
        return object.toString();
    }

    private void getClassFields(Class cla, StringBuilder builder, Object o, boolean isSubClass, int childOffset) {
        if (cla.equals(Object.class)) {
            return;
        }
        if (isSubClass) {
            builder.append(BR + BR + "=> ");
        }
        String breakLine = "";
        builder.append(cla.getSimpleName() + " {");
        Field[] fields = cla.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            field.setAccessible(true);
            if ((!cla.isMemberClass()) || (isStaticInnerClass(cla)) || (i != 0)) {
                Object subObject = null;
                try {
                    subObject = field.get(o);
                } catch (IllegalAccessException e) {
                    subObject = e;
                } finally {
                    if (subObject != null) {
                        if ((subObject instanceof String)) {
                            subObject = "\"" + subObject + "\"";
                        } else if ((subObject instanceof Character)) {
                            subObject = "'" + subObject + "'";
                        }
                        if (childOffset < 2) {
                            subObject = objectToString(subObject, childOffset + 1);
                        }
                    }
                    String formatString = breakLine + "%s = %s, ";
                    builder.append(String.format(formatString, new Object[]{field.getName(), subObject == null ? "null" : subObject
                            .toString()}));
                }
            }
        }
        if (builder.toString().endsWith("{")) {
            builder.append("}");
        } else {
            builder.replace(builder.length() - 2, builder.length() - 1, breakLine + "}");
        }
    }

    private boolean isStaticInnerClass(Class cla) {
        if ((cla != null) && (cla.isMemberClass())) {
            int modifiers = cla.getModifiers();
            if ((modifiers & 0x8) == 8) {
                return true;
            }
        }
        return false;
    }


    private String parseMap(Map map) {
        String msg = map.getClass().getName() + " [" + BR;
        Set<Object> keys = map.keySet();
        for (Object key : keys) {
            String itemString = "%s -> %s" + BR;
            Object value = map.get(key);
            if (value != null) {
                if ((value instanceof String)) {
                    value = "\"" + value + "\"";
                } else if ((value instanceof Character)) {
                    value = "'" + value + "'";
                }
            }
            msg = msg + String.format(itemString, new Object[]{objectToString(key),
                    objectToString(value)});
        }
        return msg + "]";
    }

    private String parseCollection(Collection collection) {
        if (collection == null) {
            return "";
        }
        String simpleName = collection.getClass().getName();
        String msg = "%s size = %d [" + BR;
        msg = String.format(msg, new Object[]{simpleName, Integer.valueOf(collection.size())});
        if (!collection.isEmpty()) {
            Iterator<Object> iterator = collection.iterator();
            int flag = 0;
            while (iterator.hasNext()) {
                String itemString = "[%d]:%s%s";
                Object item = iterator.next();
                msg = msg + String.format(itemString, new Object[]{Integer.valueOf(flag), objectToString(item), flag++ < collection
                        .size() - 1 ? "," + BR : BR});
            }
        }
        return msg + "]";
    }

    private String parseBundle(Bundle bundle) {
        if (bundle == null) {
            return "";
        }
        StringBuilder builder = new StringBuilder(bundle.getClass().getName() + " [" + BR);
        for (String key : bundle.keySet()) {
            builder.append(String.format("'%s' => %s " + BR, new Object[]{key,
                    objectToString(bundle.get(key))}));
        }
        builder.append("]");
        return builder.toString();
    }

    private String parseArray(Object array) {
        StringBuilder result = new StringBuilder();
        traverseArray(result, array);
        return result.toString();
    }

    public int getArrayDimension(Object object) {
        int dim = 0;
        for (int i = 0; i < object.toString().length(); i++) {
            if (object.toString().charAt(i) != '[') {
                break;
            }
            dim++;
        }
        return dim;
    }


    public char getType(Object object) {
        String str = object.toString();
        return str.substring(str.lastIndexOf("[") + 1, str.lastIndexOf("[") + 2).charAt(0);
    }

    private void traverseArray(StringBuilder result, Object array) {
        if (getArrayDimension(array) == 1) {
            switch (getType(array)) {
                case 'I':
                    result.append(Arrays.toString((int[]) array));
                    break;
                case 'D':
                    result.append(Arrays.toString((double[]) array));
                    break;
                case 'Z':
                    result.append(Arrays.toString((boolean[]) array));
                    break;
                case 'B':
                    result.append(Arrays.toString((byte[]) array));
                    break;
                case 'S':
                    result.append(Arrays.toString((short[]) array));
                    break;
                case 'J':
                    result.append(Arrays.toString((long[]) array));
                    break;
                case 'F':
                    result.append(Arrays.toString((float[]) array));
                    break;
                case 'L':
                    Object[] objects = (Object[]) array;
                    result.append("[");
                    for (int i = 0; i < objects.length; i++) {
                        result.append(objectToString(objects[i]));
                        if (i != objects.length - 1) {
                            result.append(",");
                        }
                    }
                    result.append("]");
                    break;
                case 'C':
                case 'E':
                case 'G':
                case 'H':
                case 'K':
                case 'M':
                case 'N':
                case 'O':
                case 'P':
                case 'Q':
                case 'R':
                case 'T':
                case 'U':
                case 'V':
                case 'W':
                case 'X':
                case 'Y':
                default:
                    result.append(Arrays.toString((Object[]) array));
            }
        } else {
            result.append("[");
            for (int i = 0; i < ((Object[]) array).length; i++) {
                traverseArray(result, ((Object[]) (Object[]) array)[i]);
                if (i != ((Object[]) array).length - 1) {
                    result.append(",");
                }
            }
            result.append("]");
        }
    }
}

如何打印长数据

1,循环:

    public void i(String tag, String msg) {
        if (msg.length() <= 1000) {
            Log.i(tag, msg);
        } else {
            int maxLogSize = 1000;
            for (int i = 0; i <= msg.length() / maxLogSize; i++) {
                int start = i * maxLogSize;
                int end = (i + 1) * maxLogSize;
                end = end > msg.length() ? msg.length() : end;
                i(tag, msg.substring(start, end));
            }
        }
    }

2.换行就输出:

    public void logContent(String tag, String msg) {
        String[] lines = msg.split(System.getProperty("line.separator"));// 换行符
        for (String line : lines) {
            Log.i(tag, msg);
        }
    }

其他

如何保存日记,下篇文章介绍

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值