安卓日志工具类

简易版本的处理 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()}\"" 
	        }
	    }   
}
相关推荐
程序员清洒8 小时前
Flutter for OpenHarmony:GridView — 网格布局实现
android·前端·学习·flutter·华为
running up that hill9 小时前
Android的线性布局
android
m0_748229999 小时前
Laravel9.x核心特性全解析
android
2603_9494621011 小时前
Flutter for OpenHarmony社团管理App实战:意见反馈实现
android·flutter
错把套路当深情11 小时前
android两种渠道支持一键打包 + 随意组合各种渠道
android
彬sir哥12 小时前
android studio如何把.gradle从C盘移到D盘
android·gradle·maven·android studio
、BeYourself13 小时前
TabLayout 与 ViewPager2 的基本使用
android·android-studio
南村群童欺我老无力.13 小时前
Flutter 框架跨平台鸿蒙开发 - 城市文创打卡:探索城市文化创意之旅
android·flutter·华为·harmonyos
Madison-No714 小时前
【Linux】文件操作&&重定向原理
android·linux·运维
2603_9494621015 小时前
Flutter for OpenHarmony社团管理App实战:消息中心实现
android·javascript·flutter