安卓日志工具类

简易版本的处理 Log 日志工具类,可以快速定位到出现问题的类和方法。

一、案例代码实现

第01节 java代码

java 复制代码
import android.util.Log;
import androidx.annotation.Nullable; 

/****
 *
 * @apiNote 日志工具类
 */
public class CommonLogUtil {

    public static final int LEVEL_OPEN = 1;     // 开启
    public static final int LEVEL_VERBOSE = 2;  // 冗长
    public static final int LEVEL_DEBUG = 3;    // 调试
    public static final int LEVEL_INFO = 4;     // 信息
    public static final int LEVEL_WARN = 5;     // 警告
    public static final int LEVEL_ERROR = 6;    // 错误
    public static final int LEVEL_CLOSE = 7;    // 关闭


    private static final int HEAD_NONE = 0;         // 没有头部信息
    private static final int HEAD_VERSION = 1;      // 只有版本信息
    private static final int HEAD_VERSION_CLASS = 2;    // 只有版本和类信息
    private static final int HEAD_VERSION_METHOD = 3;   // 只有版本和类方法信息
    private static final int HEAD_ALL = 4;          // 完整的头部信息


    // 初始化默认的 TAG
    private static final String FIX_TAG = "cosmo";
    // 获取当前调用栈的索引
    private static final int STACK_INDEX = 3;

    // 开启头信息
    private static final boolean isOpenHead = true;
    // 初始化默认的等级
    private static final int currentLevel = LEVEL_OPEN;
    // 初始化默认的头信息
    private static final int currentHead = HEAD_ALL;


    public static void v(String TAG, String message) {
        if (currentLevel > LEVEL_VERBOSE) {
            return;
        }
        if (isOpenHead) {
            message = formatLogHead() + message;
        }
        Log.v(TAG, message);
    }

    public static void v(String message) {
        v(FIX_TAG, message);
    }

    public static void d(String TAG, String message) {
        if (currentLevel > LEVEL_DEBUG) {
            return;
        }
        if (isOpenHead) {
            message = formatLogHead() + message;
        }
        Log.d(TAG, message);
    }

    public static void d(String message) {
        d(FIX_TAG, message);
    }

    public static void i(String TAG, String message) {
        if (currentLevel > LEVEL_INFO) {
            return;
        }
        if (isOpenHead) {
            message = formatLogHead() + message;
        }
        Log.i(TAG, message);
    }

    public static void i(String message) {
        i(FIX_TAG, message);
    }

    public static void w(String TAG, String message) {
        if (currentLevel > LEVEL_WARN) {
            return;
        }
        if (isOpenHead) {
            message = formatLogHead() + message;
        }
        Log.w(TAG, message);
    }

    public static void w(String message) {
        w(FIX_TAG, message);
    }

    public static void e(String TAG, String message) {
        if (currentLevel > LEVEL_ERROR) {
            return;
        }
        if (isOpenHead) {
            message = formatLogHead() + message;
        }
        Log.e(TAG, message);
    }

    public static void e(String message) {
        e(FIX_TAG, message);
    }


    public static String appBuildContent() {
        return FIX_TAG + "." + BuildConfig.VERSION_TIME;
    }


    /**
     * 格式化日志头部信息
     * 该方法通过获取当前调用栈来动态生成包含类名、行号和方法名的日志头部信息
     * 根据调用者是Java类还是Kotlin类来选择不同的格式
     *
     * @return 格式化的日志头部字符串,格式为 "[构建信息][类名.扩展名:行号][方法名]: "
     */
    private static String formatLogHead() {
        String result = "";

        switch (currentHead) {
            case HEAD_VERSION:
                result = getHeadVersion(result);
                break;
            case HEAD_VERSION_CLASS:
                result = getHeadVersionAndClass(result);
                break;
            case HEAD_VERSION_METHOD:
                result = getHeadAndMethodName(result);
                break;
            case HEAD_ALL:
                result = getHeadAll(result);
                break;
        }

        if (result == null) {
            return "[UNKNOWN]";
        }
        return result;
    }


    /**
     * 获取版本信息
     * 该方法通过获取当前调用栈来动态生成包含构建信息的日志头部信息
     *
     * @return 包含构建信息的日志头部字符串,格式为 "[构建信息]: "
     */
    @Nullable
    private static String getHeadVersion(String result) {
        try {
            String pattern = "[%s]: ";
            result = String.format(pattern, appBuildContent());
        } catch (Exception exception) {
            Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
        }
        return result;
    }


    /**
     * 获取版本和类信息
     * 该方法通过获取当前调用栈来动态生成包含构建信息和类名的日志头部信息
     *
     * @return 包含构建信息和类名的日志头部字符串,格式为 "[构建信息][类名.java:行号]: "
     */
    @Nullable
    private static String getHeadVersionAndClass(String result) {
        try {
            String pattern;
            String patternJava = "[%s][%s.java:%d]: ";
            String patternKotlin = "[%s][%s.kt:%d]: ";
            StackTraceElement[] stackTrace = new Throwable().getStackTrace();
            int targetIndex = 0;
            for (int i = 0; i < stackTrace.length; i++) {
                if (!stackTrace[i].getMethodName().equals("formatLogHead")) {
                    targetIndex = i;
                    break;
                }
            }
            targetIndex += STACK_INDEX;
            if (targetIndex >= stackTrace.length) {
                return null;
            }

            StackTraceElement targetElement = stackTrace[targetIndex];

            // 判断是否是 kotlin 类
            if (isKotlinClass(targetElement)) {
                pattern = patternKotlin;
            } else {
                pattern = patternJava;
            }

            String[] classNameInfo = targetElement.getClassName().split("\\.");
            String className = classNameInfo[classNameInfo.length - 1];
            className = className.contains("$") ? className.split("\\$")[0] : className;
            int lineNumber = targetElement.getLineNumber();
            result = String.format(pattern, appBuildContent(), className, lineNumber);
        } catch (Exception exception) {
            Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
        }
        return result;
    }


    /**
     * 获取类名和方法名信息
     * 该方法通过获取当前调用栈来动态生成包含类名和方法名的日志头部信息
     *
     * @return 包含类名和方法名的日志头部字符串,格式为 "[构建信息][类名.java:行号][方法名]: "
     */
    @Nullable
    private static String getHeadAndMethodName(String result) {
        try {
            String pattern;
            String patternJava = "[%s][%s]: ";
            String patternKotlin = "[%s][%s]: ";
            StackTraceElement[] stackTrace = new Throwable().getStackTrace();
            int targetIndex = 0;
            for (int i = 0; i < stackTrace.length; i++) {
                if (!stackTrace[i].getMethodName().equals("formatLogHead")) {
                    targetIndex = i;
                    break;
                }
            }
            targetIndex += STACK_INDEX;
            if (targetIndex >= stackTrace.length) {
                return null;
            }

            StackTraceElement targetElement = stackTrace[targetIndex];

            // 判断是否是 kotlin 类
            if (isKotlinClass(targetElement)) {
                pattern = patternKotlin;
            } else {
                pattern = patternJava;
            }

            String methodName = targetElement.getMethodName();
            String[] methodArray = methodName.split("\\$");
            methodName = methodName.contains("$") ? methodArray[methodArray.length - 1] : methodName;
            result = String.format(pattern, appBuildContent(), methodName);
        } catch (Exception exception) {
            Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
        }
        return result;
    }


    /**
     * 获取完整的日志头部信息
     * 该方法通过获取当前调用栈来动态生成包含类名、行号和方法名的日志头部信息
     *
     * @return 完整的日志头部字符串,格式为 "[构建信息][类名.java:行号][方法名]: "
     */
    @Nullable
    private static String getHeadAll(String result) {


        try {
            String pattern;
            String patternJava = "[%s][%s.java:%d][%s]: ";
            String patternKotlin = "[%s][%s.kt:%d][%s]: ";
            StackTraceElement[] stackTrace = new Throwable().getStackTrace();
            int targetIndex = 0;
            for (int i = 0; i < stackTrace.length; i++) {
                if (!stackTrace[i].getMethodName().equals("formatLogHead")) {
                    targetIndex = i;
                    break;
                }
            }
            targetIndex += STACK_INDEX;
            if (targetIndex >= stackTrace.length) {
                return null;
            }

            StackTraceElement targetElement = stackTrace[targetIndex];

            // 判断是否是 kotlin 类
            if (isKotlinClass(targetElement)) {
                pattern = patternKotlin;
            } else {
                pattern = patternJava;
            }

            String[] classNameInfo = targetElement.getClassName().split("\\.");
            String className = classNameInfo[classNameInfo.length - 1];
            className = className.contains("$") ? className.split("\\$")[0] : className;
            int lineNumber = targetElement.getLineNumber();
            String methodName = targetElement.getMethodName();
            String[] methodArray = methodName.split("\\$");
            methodName = methodName.contains("$") ? methodArray[methodArray.length - 1] : methodName;
            result = String.format(pattern, appBuildContent(), className, lineNumber, methodName);
        } catch (Exception exception) {
            Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
        }
        return result;
    }

    /**
     * 判断指定的堆栈元素是否为Kotlin类
     * 通过检查类上是否存在Kotlin元数据注解来判断
     *
     * @param element 要检查的堆栈跟踪元素
     * @return 如果是Kotlin类返回true,否则返回false
     */
    private static boolean isKotlinClass(StackTraceElement element) {
        try {
            Class<?> clazz = Class.forName(element.getClassName());
            return clazz.getAnnotation(kotlin.Metadata.class) != null;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

第02节 groovy语法

groovy 复制代码
static def buildSimpleTime() {
    def df = new SimpleDateFormat("yyyy-MMdd-HHmm")
    df.setTimeZone(TimeZone.getTimeZone("GMT+8:00"))
    return df.format(new Date())
}




android {
 	    buildTypes {
	        release {
	            buildConfigField "String", "VERSION_TIME", "\"${buildSimpleTime()}\"" 
	        }
	
	        debug {
	            buildConfigField "String", "VERSION_TIME", "\"${buildSimpleTime()}\"" 
	        }
	    }   
}
相关推荐
csj5020 小时前
安卓基础之《(14)—数据存储(4)应用组件Application》
android
李坤林21 小时前
Android Binder 详解(6) Binder 客户端的创建
android·binder
北京自在科技21 小时前
苹果iOS 26.3实现跨安卓数据无缝迁移
android·ios·findmy
_道隐_21 小时前
Android里面的layer、DisplayList和hardwarebuffer之间是什么关系
android
stevenzqzq1 天前
ctrl +B和ctrl+shift +B的区别
android·ide·android studio
似霰1 天前
HIDL Hal 开发笔记5----Same-Process HALs 实例分析
android·framework·hal
robotx1 天前
安卓16 设置壁纸中应用网格,有两个5X5的选项
android
Yyuanyuxin1 天前
保姆级学习开发安卓手机软件(三)--安装模拟机并开始简单的进入开发
android·学习
Android小码家1 天前
llama.cpp+Android应用定制
android·llama