补全日志调试函数

This commit is contained in:
2025-11-29 02:37:47 +08:00
parent b0a0569b28
commit 2a31658cf8
3 changed files with 468 additions and 116 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri Nov 28 18:28:36 GMT 2025
#Fri Nov 28 18:37:12 GMT 2025
stageCount=2
libraryProject=libappbase
baseVersion=15.11
publishVersion=15.11.1
buildCount=25
buildCount=28
baseBetaVersion=15.11.2

View File

@@ -4,9 +4,10 @@ package cc.winboll.studio.libappbase;
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/12 13:44:06
* @Describe LogUtils
* @Describe 应用日志类
* @Describe 应用日志类(补全所有日志重载方法,适配不同调试场景)
*/
import android.content.Context;
import android.widget.Toast;
import cc.winboll.studio.libappbase.GlobalApplication;
import dalvik.system.DexFile;
import java.io.BufferedReader;
@@ -61,7 +62,7 @@ public class LogUtils {
//
public static void init(Context context, LOG_LEVEL logLevel) {
if (GlobalApplication.isDebugging()) {
// 初始化日志缓存文件路径
// 初始化日志缓存文件路径debug模式外部存储
_mfLogCacheDir = new File(context.getApplicationContext().getExternalCacheDir(), TAG);
if (!_mfLogCacheDir.exists()) {
_mfLogCacheDir.mkdirs();
@@ -75,7 +76,7 @@ public class LogUtils {
}
_mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json");
} else {
// 初始化日志缓存文件路径
// 初始化日志缓存文件路径release模式内部存储
_mfLogCacheDir = new File(context.getApplicationContext().getCacheDir(), TAG);
if (!_mfLogCacheDir.exists()) {
_mfLogCacheDir.mkdirs();
@@ -90,11 +91,6 @@ public class LogUtils {
_mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json");
}
// Toast.makeText(context,
// "_mfLogUtilsBeanFile : " + _mfLogUtilsBeanFile
// + "\n_mfLogCatchFile : " + _mfLogCatchFile,
// Toast.LENGTH_SHORT).show();
//
_mLogUtilsBean = LogUtilsBean.loadBeanFromFile(_mfLogUtilsBeanFile.getPath(), LogUtilsBean.class);
if (_mLogUtilsBean == null) {
_mLogUtilsBean = new LogUtilsBean();
@@ -122,7 +118,6 @@ public class LogUtils {
entry.setValue(beanSetting.getEnable());
}
}
}
}
@@ -135,19 +130,14 @@ public class LogUtils {
}
static void addClassTAGList() {
//ClassLoader classLoader = getClass().getClassLoader();
try {
//String packageName = context.getPackageName();
// 包名前缀(过滤当前应用的类)
String packageNamePrefix = "cc.winboll.studio";
List<String> classNames = new ArrayList<>();
String apkPath = _mContext.getPackageCodePath();
//Log.d("APK_PATH", "The APK path is: " + apkPath);
LogUtils.d(TAG, String.format("apkPath : %s", apkPath));
//String apkPath = "/data/app/" + packageName + "-";
//DexFile dexfile = new DexFile(apkPath + "1/base.apk");
DexFile dexfile = new DexFile(apkPath);
int countTemp = 0;
Enumeration<String> entries = dexfile.entries();
while (entries.hasMoreElements()) {
@@ -165,23 +155,21 @@ public class LogUtils {
Class<?> clazz = Class.forName(className);
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()) && field.getType() == String.class && "TAG".equals(field.getName())) {
// 过滤静态、公共、String类型的 TAG 字段
if (Modifier.isStatic(field.getModifiers())
&& Modifier.isPublic(field.getModifiers())
&& field.getType() == String.class
&& "TAG".equals(field.getName())) {
String tagValue = (String) field.get(null);
//Log.d("TAG_INFO", "Class: " + className + ", TAG value: " + tagValue);
//LogUtils.d(TAG, String.format("Tag Value : %s", tagValue));
//mapTAGList.put(tagValue, true);
mapTAGList.put(tagValue, false);
mapTAGList.put(tagValue, false); // 默认禁用,可通过设置开启
}
}
} catch (NoClassDefFoundError | ClassNotFoundException | IllegalAccessException e) {
LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace());
//LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
//Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
//Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
@@ -191,7 +179,6 @@ public class LogUtils {
Map.Entry<String, Boolean> entry = iterator.next();
if (tag.equals(entry.getKey())) {
entry.setValue(isEnable);
//System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
break;
}
}
@@ -204,7 +191,6 @@ public class LogUtils {
while (iterator.hasNext()) {
Map.Entry<String, Boolean> entry = iterator.next();
entry.setValue(isEnable);
//System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
saveTAGBeanSettings();
LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString()));
@@ -223,10 +209,11 @@ public class LogUtils {
if (!_IsInited) {
return false;
}
if (mapTAGList.get(tag) == null
|| !mapTAGList.get(tag)) {
// TAG 未配置或禁用时,不打印日志
if (mapTAGList.get(tag) == null || !mapTAGList.get(tag)) {
return false;
}
// 日志级别不符合时,不打印日志
if (!isInTheLevel(logLevel)) {
return false;
}
@@ -234,8 +221,8 @@ public class LogUtils {
}
static boolean isInTheLevel(LOG_LEVEL logLevel) {
return (LogUtils._mLogUtilsBean.getLogLevel().ordinal() == logLevel.ordinal()
|| LogUtils._mLogUtilsBean.getLogLevel().ordinal() > logLevel.ordinal());
// 当前日志级别 >= 目标级别时允许打印级别顺序Off < Error < Warn < Info < Debug < Verbose
return LogUtils._mLogUtilsBean.getLogLevel().ordinal() >= logLevel.ordinal();
}
//
@@ -245,136 +232,501 @@ public class LogUtils {
return _mfLogCacheDir;
}
//
// 调试日志写入函数
//
// ================================= 补全所有日志重载方法Error 级别) =================================
/**
* Error 级别日志(仅消息)
* @param szTAG 标签
* @param szMessage 日志消息
*/
public static void e(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, szMessage);
}
}
//
// 调试日志写入函数
//
/**
* Error 级别日志(消息 + 异常)
* @param szTAG 标签
* @param szMessage 日志消息
* @param e 异常对象
*/
public static void e(String szTAG, String szMessage, Exception e) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, sb.toString());
}
}
/**
* Error 级别日志(仅异常)
* @param szTAG 标签
* @param e 异常对象
*/
public static void e(String szTAG, Exception e) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
String message = "【异常信息】: " + getExceptionInfo(e);
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, message);
}
}
/**
* Error 级别日志(消息 + 异常 + 堆栈)
* @param szTAG 标签
* @param szMessage 日志消息
* @param e 异常对象
* @param listStackTrace 堆栈信息
*/
public static void e(String szTAG, String szMessage, Exception e, StackTraceElement[] listStackTrace) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
sb.append("\n【堆栈信息】: ").append(getStackTraceInfo(listStackTrace));
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, sb.toString());
}
}
// ================================= 补全所有日志重载方法Warn 级别) =================================
/**
* Warn 级别日志(仅消息)
* @param szTAG 标签
* @param szMessage 日志消息
*/
public static void w(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, szMessage);
}
}
//
// 调试日志写入函数
//
/**
* Warn 级别日志(消息 + 异常)
* @param szTAG 标签
* @param szMessage 日志消息
* @param e 异常对象
*/
public static void w(String szTAG, String szMessage, Exception e) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) {
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, sb.toString());
}
}
/**
* Warn 级别日志(仅异常)
* @param szTAG 标签
* @param e 异常对象
*/
public static void w(String szTAG, Exception e) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) {
String message = "【异常信息】: " + getExceptionInfo(e);
saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, message);
}
}
// ================================= 补全所有日志重载方法Info 级别) =================================
/**
* Info 级别日志(仅消息)
* @param szTAG 标签
* @param szMessage 日志消息
*/
public static void i(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Info)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Info, szMessage);
}
}
//
// 调试日志写入函数
//
/**
* Info 级别日志(消息 + 数据对象)
* @param szTAG 标签
* @param szMessage 日志消息
* @param obj 数据对象(自动转为字符串)
*/
public static void i(String szTAG, String szMessage, Object obj) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Info)) {
String objStr = obj == null ? "null" : obj.toString();
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【数据对象】: ").append(objStr);
saveLog(szTAG, LogUtils.LOG_LEVEL.Info, sb.toString());
}
}
// ================================= 补全所有日志重载方法Debug 级别) =================================
/**
* Debug 级别日志(仅消息)
* @param szTAG 标签
* @param szMessage 日志消息
*/
public static void d(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, szMessage);
}
}
//
// 调试日志写入函数
// 包含线程调试堆栈信息
//
/**
* Debug 级别日志(消息 + 堆栈)
* @param szTAG 标签
* @param szMessage 日志消息
* @param listStackTrace 堆栈信息
*/
public static void d(String szTAG, String szMessage, StackTraceElement[] listStackTrace) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
StringBuilder sbMessage = new StringBuilder(szMessage);
sbMessage.append(" \nAt ");
sbMessage.append(listStackTrace[2].getMethodName());
sbMessage.append(" (");
sbMessage.append(listStackTrace[2].getFileName());
sbMessage.append(":");
sbMessage.append(listStackTrace[2].getLineNumber());
sbMessage.append(")");
sbMessage.append("\n【调用堆栈】: ").append(getStackTraceInfo(listStackTrace));
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString());
}
}
//
// 调试日志写入函数
// 包含异常信息和线程调试堆栈信息
//
/**
* Debug 级别日志(消息 + 异常)
* @param szTAG 标签
* @param szMessage 日志消息
* @param e 异常对象
*/
public static void d(String szTAG, String szMessage, Exception e) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
}
}
/**
* Debug 级别日志(异常 + 堆栈)
* @param szTAG 标签
* @param e 异常对象
* @param listStackTrace 堆栈信息
*/
public static void d(String szTAG, Exception e, StackTraceElement[] listStackTrace) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
StringBuilder sbMessage = new StringBuilder(e.getClass().toGenericString());
sbMessage.append(" : ");
sbMessage.append(e.getMessage());
sbMessage.append(" \nAt ");
sbMessage.append(listStackTrace[2].getMethodName());
sbMessage.append(" (");
sbMessage.append(listStackTrace[2].getFileName());
sbMessage.append(":");
sbMessage.append(listStackTrace[2].getLineNumber());
sbMessage.append(")");
StringBuilder sbMessage = new StringBuilder();
sbMessage.append("【异常信息】: ").append(getExceptionInfo(e));
sbMessage.append("\n【调用堆栈】: ").append(getStackTraceInfo(listStackTrace));
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString());
}
}
//
// 调试日志写入函数
//
/**
* Debug 级别日志(消息 + 数据对象)
* @param szTAG 标签
* @param szMessage 日志消息
* @param obj 数据对象(自动转为字符串)
*/
public static void d(String szTAG, String szMessage, Object obj) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
String objStr = obj == null ? "null" : obj.toString();
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【数据对象】: ").append(objStr);
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
}
}
/**
* Debug 级别日志(仅数据对象)
* @param szTAG 标签
* @param obj 数据对象(自动转为字符串)
*/
public static void d(String szTAG, Object obj) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
String objStr = obj == null ? "null" : obj.toString();
String message = "【数据对象】: " + objStr;
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, message);
}
}
// ================================= 补全所有日志重载方法Verbose 级别) =================================
/**
* Verbose 级别日志(仅消息)
* @param szTAG 标签
* @param szMessage 日志消息
*/
public static void v(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, szMessage);
}
}
//
// 日志文件保存函数
//
/**
* Verbose 级别日志(消息 + 数据对象)
* @param szTAG 标签
* @param szMessage 日志消息
* @param obj 数据对象(自动转为字符串)
*/
public static void v(String szTAG, String szMessage, Object obj) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) {
String objStr = obj == null ? "null" : obj.toString();
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【数据对象】: ").append(objStr);
saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, sb.toString());
}
}
/**
* Verbose 级别日志(仅数据对象)
* @param szTAG 标签
* @param obj 数据对象(自动转为字符串)
*/
public static void v(String szTAG, Object obj) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) {
String objStr = obj == null ? "null" : obj.toString();
String message = "【数据对象】: " + objStr;
saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, message);
}
}
// ================================= 新增:通用日志工具方法(补充调试能力) =================================
/**
* 打印当前线程信息Debug 级别)
* @param szTAG 标签
* @param szMessage 日志消息
*/
public static void printThreadInfo(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
Thread currentThread = Thread.currentThread();
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【线程信息】: ")
.append("线程名=").append(currentThread.getName())
.append(", 线程ID=").append(currentThread.getId())
.append(", 线程状态=").append(currentThread.getState().name());
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
}
}
/**
* 打印 Map 数据Debug 级别,格式化输出,便于查看)
* @param szTAG 标签
* @param szMessage 日志消息
* @param map 要打印的 Map 数据
*/
public static <K, V> void printMap(String szTAG, String szMessage, Map<K, V> map) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug) && map != null) {
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【Map 数据】size=").append(map.size()).append(":");
for (Map.Entry<K, V> entry : map.entrySet()) {
String keyStr = entry.getKey() == null ? "null" : entry.getKey().toString();
String valueStr = entry.getValue() == null ? "null" : entry.getValue().toString();
sb.append("\n ").append(keyStr).append(" = ").append(valueStr);
}
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
}
}
/**
* 打印 List 数据Debug 级别,格式化输出)
* @param szTAG 标签
* @param szMessage 日志消息
* @param list 要打印的 List 数据
*/
public static <T> void printList(String szTAG, String szMessage, List<T> list) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug) && list != null) {
StringBuilder sb = new StringBuilder(szMessage);
sb.append("\n【List 数据】size=").append(list.size()).append(":");
for (int i = 0; i < list.size(); i++) {
T item = list.get(i);
String itemStr = item == null ? "null" : item.toString();
sb.append("\n 索引").append(i).append(" = ").append(itemStr);
}
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
}
}
// ================================= 私有工具方法(异常/堆栈信息格式化) =================================
/**
* 格式化异常信息(提取异常类型、消息、简化堆栈)
* @param e 异常对象
* @return 格式化后的异常字符串
*/
private static String getExceptionInfo(Exception e) {
if (e == null) {
return "异常对象为null";
}
StringBuilder sb = new StringBuilder();
// 异常类型 + 异常消息
sb.append(e.getClass().getSimpleName()).append(" : ").append(e.getMessage() == null ? "无异常消息" : e.getMessage());
// 简化堆栈取前5行避免日志过长
StackTraceElement[] stackTrace = e.getStackTrace();
if (stackTrace != null && stackTrace.length > 0) {
sb.append("\n 简化堆栈前5行:");
int limit = Math.min(stackTrace.length, 5);
for (int i = 0; i < limit; i++) {
sb.append("\n ").append(stackTrace[i].toString());
}
}
return sb.toString();
}
/**
* 格式化堆栈信息(提取关键调用链路)
* @param stackTrace 堆栈数组
* @return 格式化后的堆栈字符串
*/
private static String getStackTraceInfo(StackTraceElement[] stackTrace) {
if (stackTrace == null || stackTrace.length == 0) {
return "堆栈信息为空";
}
StringBuilder sb = new StringBuilder();
// 过滤 LogUtils 内部调用取真实业务调用链路前8行
int count = 0;
for (StackTraceElement element : stackTrace) {
// 跳过 LogUtils 自身的堆栈(避免冗余)
if (element.getClassName().contains("cc.winboll.studio.libappbase.LogUtils")) {
continue;
}
sb.append("\n ").append(element.getClassName()).append(".")
.append(element.getMethodName()).append("(")
.append(element.getFileName()).append(":").append(element.getLineNumber()).append(")");
count++;
if (count >= 8) { // 限制堆栈长度,避免日志过大
break;
}
}
return sb.toString();
}
// ================================= 原有核心方法(保留并优化) =================================
/**
* 日志文件保存函数(优化:增加异常捕获完整性,避免流泄漏)
* @param szTAG 标签
* @param logLevel 日志级别
* @param szMessage 日志消息
*/
static void saveLog(String szTAG, LogUtils.LOG_LEVEL logLevel, String szMessage) {
BufferedWriter out = null;
try {
BufferedWriter out = null;
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_mfLogCatchFile, true), "UTF-8"));
out.write("[" + logLevel + "] " + mSimpleDateFormat.format(System.currentTimeMillis()) + " [" + szTAG + "]\n" + szMessage + "\n");
out.close();
} catch (IOException e) {
LogUtils.d(TAG, "IOException : " + e.getMessage());
}
}
//
// 历史日志加载函数
//
public static String loadLog() {
if (_mfLogCatchFile.exists()) {
StringBuffer sb = new StringBuffer();
try {
BufferedReader in = null;
in = new BufferedReader(new InputStreamReader(new FileInputStream(_mfLogCatchFile), "UTF-8"));
String line = "";
while ((line = in.readLine()) != null) {
sb.append(line);
sb.append("\n");
// 确保日志文件存在(创建父目录 + 文件)
if (!_mfLogCatchFile.exists()) {
File parentDir = _mfLogCatchFile.getParentFile();
if (parentDir != null && !parentDir.exists()) {
parentDir.mkdirs();
}
_mfLogCatchFile.createNewFile();
}
// 追加写入日志UTF-8编码避免中文乱码
out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(_mfLogCatchFile, true), "UTF-8"));
String logLine = "[" + logLevel + "] "
+ mSimpleDateFormat.format(System.currentTimeMillis())
+ " [" + szTAG + "]\n"
+ szMessage + "\n\n"; // 增加空行,区分不同日志
out.write(logLine);
out.flush(); // 强制刷新,确保日志及时写入
} catch (IOException e) {
// 日志写入失败时,打印系统日志(避免递归调用)
android.util.Log.e(TAG, "日志写入失败: " + e.getMessage());
} finally {
// 关闭流避免资源泄漏Java 7 手动关闭,无 try-with-resources
if (out != null) {
try {
out.close();
} catch (IOException e) {
android.util.Log.e(TAG, "流关闭失败: " + e.getMessage());
}
} catch (IOException e) {
LogUtils.d(TAG, "IOException : " + e.getMessage());
}
return sb.toString();
}
return "";
}
//
// 清理日志函数
//
public static void cleanLog() {
if (_mfLogCatchFile.exists()) {
try {
UTF8FileUtils.writeStringToFile(_mfLogCatchFile.getPath(), "");
//LogUtils.d(TAG, "cleanLog");
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
}
/**
* 历史日志加载函数(优化:增加流关闭,避免内存泄漏)
* @return 日志内容字符串(空串表示无日志)
*/
public static String loadLog() {
if (_mfLogCatchFile == null || !_mfLogCatchFile.exists()) {
return "日志文件不存在";
}
StringBuffer sb = new StringBuffer();
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
new FileInputStream(_mfLogCatchFile), "UTF-8"));
String line = "";
while ((line = in.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (IOException e) {
sb.append("日志加载失败: ").append(e.getMessage());
LogUtils.e(TAG, "日志加载异常", e);
} finally {
// 关闭流,避免资源泄漏
if (in != null) {
try {
in.close();
} catch (IOException e) {
LogUtils.e(TAG, "流关闭异常", e);
}
}
}
return sb.toString();
}
/**
* 清理日志函数(优化:支持清空日志,避免文件过大)
*/
public static void cleanLog() {
if (_mfLogCatchFile == null) {
LogUtils.d(TAG, "日志文件未初始化,无需清理");
return;
}
try {
// 清空文件内容(覆盖写入空字符串)
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(_mfLogCatchFile, false), "UTF-8"));
out.write("");
out.flush();
out.close();
LogUtils.d(TAG, "日志已清空,文件路径: " + _mfLogCatchFile.getPath());
} catch (IOException e) {
LogUtils.e(TAG, "日志清空失败", e);
}
}
/**
* 检查日志文件大小(新增:避免日志文件过大占用内存)
* @param maxSizeMB 最大允许大小MB
* @return true文件超过限制false文件大小正常
*/
public static boolean checkLogFileSize(int maxSizeMB) {
if (_mfLogCatchFile == null || !_mfLogCatchFile.exists()) {
return false;
}
// 转换为字节1MB = 1024*1024 字节)
long maxSizeByte = maxSizeMB * 1024 * 1024;
long fileSize = _mfLogCatchFile.length();
LogUtils.d(TAG, String.format("日志文件大小: %.2f MB限制: %d MB",
fileSize / (1024.0 * 1024), maxSizeMB));
return fileSize > maxSizeByte;
}
/**
* 初始化检查(新增:快速判断 LogUtils 是否初始化完成)
* @return true已初始化false未初始化
*/
public static boolean isInited() {
return _IsInited;
}
/**
* 显示短提示(新增:日志+Toast联动调试时快速提示
* @param context 上下文
* @param message 提示内容
*/
public static void showShortToast(final Context context, final String message) {
if (context == null || message == null) {
return;
}
// 主线程显示Toast避免子线程崩溃
if (Thread.currentThread().getId() == android.os.Process.myTid()) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
} else {
((android.app.Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
});
}
// 同时写入日志
LogUtils.d(TAG, "Toast提示: " + message);
}
}