源码整理
This commit is contained in:
@@ -4,77 +4,138 @@ package cc.winboll.studio.libappbase;
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2024/08/12 14:43:50
|
||||
* @Describe 日志视图线程类
|
||||
* 独立线程监听日志文件目录变化(如写入、删除),触发日志视图更新,避免阻塞主线程
|
||||
*/
|
||||
import android.os.FileObserver;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class LogViewThread extends Thread {
|
||||
|
||||
/** 日志标签(用于调试输出) */
|
||||
public static final String TAG = "LogViewThread";
|
||||
|
||||
// 线程退出标志
|
||||
volatile boolean isExist = false;
|
||||
// 应用日志文件监听实例
|
||||
LogListener mLogListener;
|
||||
// 日志视图弱引用
|
||||
WeakReference<LogView> mwrLogView;
|
||||
/** 线程退出标志(volatile 保证多线程可见性,控制循环退出) */
|
||||
private volatile boolean isExit = false;
|
||||
/** 日志文件目录监听实例(监听文件写入、删除事件) */
|
||||
private LogListener mLogListener;
|
||||
/** 日志视图弱引用(避免持有 LogView 强引用导致内存泄漏) */
|
||||
private final WeakReference<LogView> mLogViewWeakRef;
|
||||
|
||||
//
|
||||
// 构造函数
|
||||
// @logView : 日志显示输出视图类
|
||||
/**
|
||||
* 构造函数
|
||||
* @param logView 日志显示视图实例(需通过弱引用持有,避免内存泄漏)
|
||||
*/
|
||||
public LogViewThread(LogView logView) {
|
||||
mwrLogView = new WeakReference<LogView>(logView);
|
||||
|
||||
// 使用弱引用包装 LogView,当视图销毁时可被 GC 回收
|
||||
mLogViewWeakRef = new WeakReference<>(logView);
|
||||
}
|
||||
|
||||
public void setIsExist(boolean isExist) {
|
||||
this.isExist = isExist;
|
||||
/**
|
||||
* 设置线程退出标志(触发线程停止监听并退出)
|
||||
* @param exit true:退出线程;false:继续运行(默认)
|
||||
*/
|
||||
public void setExit(boolean exit) {
|
||||
this.isExit = exit;
|
||||
}
|
||||
|
||||
public boolean isExist() {
|
||||
return isExist;
|
||||
/**
|
||||
* 获取当前线程退出状态
|
||||
* @return true:已标记退出;false:运行中
|
||||
*/
|
||||
public boolean isExit() {
|
||||
return isExit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 线程核心逻辑:初始化文件监听并启动循环,直到收到退出标志
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
String szLogDir = LogUtils.getLogCacheDir().getPath();
|
||||
mLogListener = new LogListener(szLogDir);
|
||||
// 获取日志缓存目录路径(从 LogUtils 统一获取,确保路径一致性)
|
||||
String logDirPath = LogUtils.getLogCacheDir().getPath();
|
||||
LogUtils.d(TAG, "启动日志文件监听,监听目录:" + logDirPath);
|
||||
|
||||
// 初始化日志文件监听器(监听目标目录的文件事件)
|
||||
mLogListener = new LogListener(logDirPath);
|
||||
// 开始监听文件事件(非阻塞,内部通过 Native 层实现)
|
||||
mLogListener.startWatching();
|
||||
while (isExist() == false) {
|
||||
|
||||
// 循环等待退出标志(每 1 秒检查一次,降低 CPU 占用)
|
||||
while (!isExit()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {}
|
||||
Thread.sleep(1000); // 休眠 1 秒,避免忙等
|
||||
} catch (InterruptedException e) {
|
||||
// 线程被中断时,恢复中断标志并退出循环(避免无限阻塞)
|
||||
Thread.currentThread().interrupt();
|
||||
LogUtils.d(TAG, "日志监听线程被中断,准备退出。" + e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 收到退出标志,停止监听并释放资源
|
||||
mLogListener.stopWatching();
|
||||
LogUtils.d(TAG, "日志文件监听已停止,线程退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志文件监听内部类(继承 FileObserver,监听目录下文件变化)
|
||||
* 仅关注文件写入完成(CLOSE_WRITE)和文件删除(DELETE)事件
|
||||
*/
|
||||
private class LogListener extends FileObserver {
|
||||
|
||||
//
|
||||
// 日志文件监听类
|
||||
//
|
||||
class LogListener extends FileObserver {
|
||||
/**
|
||||
* 构造函数
|
||||
* @param path 监听的目录路径(此处为日志缓存目录)
|
||||
*/
|
||||
public LogListener(String path) {
|
||||
// 父类构造:监听指定目录的所有事件(通过位掩码 ALL_EVENTS 指定)
|
||||
super(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件事件回调(运行在系统私有线程,非主线程)
|
||||
* @param event 事件类型(通过位掩码表示,需与 ALL_EVENTS 按位与解析)
|
||||
* @param path 发生事件的文件名(相对监听目录的路径)
|
||||
*/
|
||||
@Override
|
||||
public void onEvent(int event, String path) {
|
||||
int e = event & FileObserver.ALL_EVENTS;
|
||||
switch (e) {
|
||||
case FileObserver.CLOSE_WRITE:{
|
||||
if (mwrLogView.get() != null) {
|
||||
mwrLogView.get().updateLogView();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FileObserver.DELETE:{
|
||||
if (mwrLogView.get() != null) {
|
||||
mwrLogView.get().updateLogView();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// 解析事件类型(排除无关事件,只处理目标事件)
|
||||
int eventType = event & FileObserver.ALL_EVENTS;
|
||||
|
||||
switch (eventType) {
|
||||
// 事件:文件写入完成(如日志写入结束并关闭文件)
|
||||
case FileObserver.CLOSE_WRITE:
|
||||
LogUtils.d(TAG, "日志文件写入完成,文件名:" + (path != null ? path : "未知"));
|
||||
// 触发日志视图更新(需先判断 LogView 是否未被回收)
|
||||
updateLogView();
|
||||
break;
|
||||
|
||||
// 事件:文件被删除(如日志清理操作)
|
||||
case FileObserver.DELETE:
|
||||
LogUtils.d(TAG, "日志文件被删除,文件名:" + (path != null ? path : "未知"));
|
||||
// 触发日志视图更新(刷新视图显示空状态)
|
||||
updateLogView();
|
||||
break;
|
||||
|
||||
default:
|
||||
// 忽略其他无关事件(如文件创建、访问等)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发日志视图更新(通过弱引用获取 LogView,避免内存泄漏)
|
||||
*/
|
||||
private void updateLogView() {
|
||||
// 从弱引用中获取 LogView 实例(若视图已销毁,get() 返回 null)
|
||||
LogView logView = mLogViewWeakRef.get();
|
||||
if (logView != null) {
|
||||
// 调用 LogView 的更新方法(需确保 updateLogView 内部处理主线程切换)
|
||||
logView.updateLogView();
|
||||
} else {
|
||||
LogUtils.w(TAG, "LogView 已被回收,无法更新日志视图");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user