96SEO 2026-09-05 13:58 33
其实,
日志往往会被程序截断、丢失。或者占用过多内存,为了解决这些痛点,可以通过自定义本地日志写入工具,将日志持久化到磁盘,而且具备以下特性:
package com.eternal.base.utils;import android.content.Context;说起来,import android.os.Environment;import android.util.Log;import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;按理说,import java.io.PrintWriter;import java.io.StringWriter;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Locale;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**
* 本地日志写入工具类
*
* 功能:
* • 支持多级别日志
* • 异步写入,不阻塞主线程
* • 自动按日期分文件
* • 线程安全
* • 支持异常堆栈记录
* • 自动清理过期日志
*
* 使用示例:
*
* // 初始化
* WriteFileLog.init;怎么说呢,*
* // 写日志
* WriteFileLog.i;* WriteFileLog.e;*/
public class WriteFileLog {
private static final String TAG = "WriteFileLog";/** 日志级别常量 */
private static final String LEVEL_INFO = "I";private static final String LEVEL_WARN = "W";private static final String LEVEL_ERROR = "E";private static final String LEVEL_DEBUG = "D";/** 日志文件后缀 */
private static final String LOG_SUFFIX = ".log";/** 日志文件夹名称 */
private static final String LOG_DIR_NAME = "logs";/** 单个日志文件保留天数,超过自动删除 */
private static final int RETAIN_DAYS = 7;/** 单个日志文件最大大小,超过则自动滚动生成新文件 */
private static final long MAX_FILE_SIZE = 10L * 1024L * 1024L;话说回来,// 10MB
private static volatile boolean sInitialized = false;private static File sLogDir;/** 单线程写入器,保证线程安全且按顺序落盘 */
private static final ExecutorService sExecutor =
Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread;t.setDaemon,t.setPriority;说起来,return t;}),private static final SimpleDateFormat FILE_DATE_FORMAT =
new SimpleDateFormat;怎么说呢,private static final SimpleDateFormat LOG_DATE_FORMAT =
new SimpleDateFormat;private WriteFileLog {
throw new UnsupportedOperationException;怎么说呢,}
/**
* 初始化日志工具类。建议在 {@code Application.onCreate} 中调用一次。老实说,*
* @param context 应用上下文
*/
public static void init {
if {
Log.e;return,}
Context app = context.getApplicationContext;File externalDir =
app.getExternalFilesDir;话说回来,// 无需 WRITE_EXTERNAL_STORAGE 权限
if {
externalDir = app.getFilesDir;// 回退到内部 storage
}
sLogDir = new File;if &&,sLogDir.mkdirs) {
Log.e(TAG,"init: failed to create log dir: "
+ sLogDir.getAbsolutePath);}
sInitialized = true;// 启动时清理过期日志
cleanExpiredLogs;Log.i(TAG,"WriteFileLog initialized。log dir: "
+ sLogDir.getAbsolutePath);
}
public static File getLogDir { return sLogDir;}
/* ---------------------- 对外 API ---------------------- */
public static void i { write;}
public static void w { write;话说回来,}
public static void w(String tag。String msg,Throwable tr) { write;}
public static void e(String tag。String msg) { write(LEVEL_ERROR,tag,msg,null);}
public static void e(String tag,String msg。Throwable tr) { write(LEVEL_ERROR,tag,msg,tr);}
public static void d(String tag。String msg) { write(LEVEL_DEBUG,tag,msg,null);说起来,}
/**
* 通用写入方法。*
* @param level 日志级别
* @param tag 标签
* @param msg 消息内容
* @param tr 可选的异常堆栈
*/
public static void write(final String level,final String tag。final String msg,final Throwable tr) {
if {
// 未初始化时仅打印到 Logcat,避免丢失关键信息
Log.w(TAG,"WriteFileLog not initialized,"
+ " fallback to Logcat");return,}
long timestamp =
System.currentTimeMillis;String threadName =
Thread.currentThread
.getName;// 在主调线程同步获取调用位置,异步后拿不到真实调用栈
final String caller =
getCallerInfo;sExecutor.execute ->
doWrite(level。tag,msg,tr,timestamp,threadName,caller));}
/* ---------------------- 内部实现 ---------------------- */
/**
* 根据时间戳解析当前要写入的日志文件。*
*
** 超过 {@link #MAX_FILE_SIZE} 时自动滚动。**/
private
static
File resolveLogFile{String date=
formatTime);/*先尝试基础文件名*/
File base=new File;if||base.length{long cutoff=System.currentTimeMillis-RETAIN_DAYS*24L*
60L*
60L*
1000L;不过,File files=sLogDir.listFiles;ifreturn,int deleted=0;for{if&&f.lastModified{File files=slogdir.listFiles;ifreturn,for{if)f.delete;}
Log.i,});}
/** 判断 SD 卡是否可用。用于外部写入前预检,按理说,**/
public
static
boolean isExternalStorageWritable{String state=
Environment.
getExternalStorageState;return Environment.MEDIA_MOUNTED.equals;说起来,}
}
@Override
public void onCreate {
super.onCreate;try {
// 若关闭位置权限会重新启动App,而不启动MainActivity。通过反射重新初始化MainModel
this.mViewModel=createViewModel;} catch {
Klog.e;}
if{
Writefilelog.init;//只在 DEBUG 模式下开启本地持久化,可进一步减少正式环境占用空间
}
}
通过上述实现,你可以在任何地方使用 WriteFileLog.i/w/e/d 写入不同级别的日志。同时后台会把它们异步保存到磁盘,而且会根据配置自动分割、滚动和清理旧文件,从而解决“无法定位崩溃点”“硬盘空间被大量占用”还有“长期运行应用崩溃未捕获”的痛点。话说回来,

小贴士:
CreateInit 放到 `BuildConfig.DEBUG` 判断块内。可避免正式版本无谓占用磁盘。`
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback