java 自动清除日志_Android全局捕获崩溃异常记录日志保存至本地并定时删除

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

import android.widget.TextView;

public class MainActivity extends Activity {

private TextView tv;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tv.setText("我没初始化");

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);

return true;

}

}

Appcation与Thread.UncaughtExceptionHandler

Appcation:Application和Activity,Service一样,是android框架的一个系统组件,当android程序启动时系统会创建一个 application对象,用来存储系统的一些信息。通常我们是不需要指定一个Application的,这时系统会自动帮我们创建,如果需要创建自己 的Application,也很简单创建一个类继承 Application并在manifest的application标签中进行注册(只需要给Application标签增加个name属性把自己的 Application的名字定入即可)。

android系统会为每个程序运行时创建一个Application类的对象且仅创建一个,所以Application可以说是单例 (singleton)模式的一个类.且application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。因为它是全局 的单例的,所以在不同的Activity,Service中获得的对象都是同一个对象。所以通过Application来进行一些,数据传递,数据共享 等,数据缓存等操作。

Thread.UncaughtExceptionHandler:当某一线程因未捕获的异常而即将终止时,Java 虚拟机将使用 Thread.getUncaughtExceptionHandler() 查询该线程以获得其 UncaughtExceptionHandler 的线程,并调用处理程序的uncaughtException 方法,将线程和异常作为参数传递。如果某一线程没有明确设置其UncaughtExceptionHandler,则将它的ThreadGroup 对象作为其UncaughtExceptionHandler。如果ThreadGroup 对象对处理异常没有什么特殊要求,那么它可以将调用转发给默认的未捕获异常处理程序。

我们需要实现此接口,并注册为程序中默认未捕获异常处理。这样当未捕获异常发生时,就可以做一些个性化的异常处理操作。

日志代码类

import java.io.File;

import java.io.FileOutputStream;

import java.io.FilenameFilter;

import java.io.PrintWriter;

import java.io.StringWriter;

import java.io.Writer;

import java.lang.Thread.UncaughtExceptionHandler;

import java.lang.reflect.Field;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

import android.annotation.SuppressLint;

import android.content.Context;

import android.content.Intent;

import android.content.pm.PackageInfo;

import android.content.pm.PackageManager;

import android.content.pm.PackageManager.NameNotFoundException;

import android.os.Build;

import android.os.Environment;

import android.os.Looper;

import android.os.SystemClock;

import android.util.Log;

import android.widget.Toast;

/**

*

全局捕获异常

*

* 当程序发生Uncaught异常的时候,有该类来接管程序,并记录错误日志

*

*/

@SuppressLint("SimpleDateFormat")

public class CrashHandler implements UncaughtExceptionHandler {

public static String TAG = "MyCrash";

// 系统默认的UncaughtException处理类

private Thread.UncaughtExceptionHandler mDefaultHandler;

private static CrashHandler instance = new CrashHandler();

private Context mContext;

// 用来存储设备信息和异常信息

private Map infos = new HashMap();

// 用于格式化日期,作为日志文件名的一部分

private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

/** 保证只有一个CrashHandler实例 */

private CrashHandler() {

}

/** 获取CrashHandler实例 ,单例模式 */

public static CrashHandler getInstance() {

return instance;

}

/**

* 初始化

*

* @param context

*/

public void init(Context context) {

mContext = context;

// 获取系统默认的UncaughtException处理器

mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();

// 设置该CrashHandler为程序的默认处理器

Thread.setDefaultUncaughtExceptionHandler(this);

autoClear(5);

}

/**

* 当UncaughtException发生时会转入该函数来处理

*/

@Override

public void uncaughtException(Thread thread, Throwable ex) {

if (!handleException(ex) && mDefaultHandler != null) {

// 如果用户没有处理则让系统默认的异常处理器来处理

mDefaultHandler.uncaughtException(thread, ex);

} else {

SystemClock.sleep(3000);

// 退出程序

android.os.Process.killProcess(android.os.Process.myPid());

System.exit(1);

}

}

/**

* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.

*

* @param ex

* @return true:如果处理了该异常信息; 否则返回false.

*/

private boolean handleException(Throwable ex) {

if (ex == null)

return false;

try {

// 使用Toast来显示异常信息

new Thread() {

@Override

public void run() {

Looper.prepare();

Toast.makeText(mContext, "很抱歉,程序出现异常,即将重启.",

Toast.LENGTH_LONG).show();

Looper.loop();

}

}.start();

// 收集设备参数信息

collectDeviceInfo(mContext);

// 保存日志文件

saveCrashInfoFile(ex);

SystemClock.sleep(3000);

} catch (Exception e) {

e.printStackTrace();

}

return true;

}

/**

* 收集设备参数信息

*

* @param ctx

*/

public void collectDeviceInfo(Context ctx) {

try {

PackageManager pm = ctx.getPackageManager();

PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),

PackageManager.GET_ACTIVITIES);

if (pi != null) {

String versionName = pi.versionName + "";

String versionCode = pi.versionCode + "";

infos.put("versionName", versionName);

infos.put("versionCode", versionCode);

}

} catch (NameNotFoundException e) {

Log.e(TAG, "an error occured when collect package info", e);

}

Field[] fields = Build.class.getDeclaredFields();

for (Field field : fields) {

try {

field.setAccessible(true);

infos.put(field.getName(), field.get(null).toString());

} catch (Exception e) {

Log.e(TAG, "an error occured when collect crash info", e);

}

}

}

/**

* 保存错误信息到文件中

* @param ex

* @return 返回文件名称,便于将文件传送到服务器

* @throws Exception

*/

private String saveCrashInfoFile(Throwable ex) throws Exception {

StringBuffer sb = new StringBuffer();

try {

SimpleDateFormat sDateFormat = new SimpleDateFormat(

"yyyy-MM-dd HH:mm:ss");

String date = sDateFormat.format(new java.util.Date());

sb.append("\r\n" + date + "\n");

for (Map.Entry entry : infos.entrySet()) {

String key = entry.getKey();

String value = entry.getValue();

sb.append(key + "=" + value + "\n");

}

Writer writer = new StringWriter();

PrintWriter printWriter = new PrintWriter(writer);

ex.printStackTrace(printWriter);

Throwable cause = ex.getCause();

while (cause != null) {

cause.printStackTrace(printWriter);

cause = cause.getCause();

}

printWriter.flush();

printWriter.close();

String result = writer.toString();

sb.append(result);

String fileName = writeFile(sb.toString());

return fileName;

} catch (Exception e) {

Log.e(TAG, "an error occured while writing file...", e);

sb.append("an error occured while writing file...\r\n");

writeFile(sb.toString());

}

return null;

}

private String writeFile(String sb) throws Exception {

String time = formatter.format(new Date());

String fileName = "crash-" + time + ".log";

if (FileUtil.hasSdcard()) {

String path = getGlobalpath();

File dir = new File(path);

if (!dir.exists())

dir.mkdirs();

String filePath = path + fileName;

File txtFile = new File(filePath);

if (!txtFile.exists())

txtFile.createNewFile();

FileOutputStream fos = new FileOutputStream(txtFile, true);

fos.write(sb.getBytes());

fos.flush();

fos.close();

}

return fileName;

}

public static String getGlobalpath() {

return Environment.getExternalStorageDirectory().getAbsolutePath()

+ File.separator + "crash" + File.separator;

}

public static void setTag(String tag) {

TAG = tag;

}

/**

* 文件删除

* @param day 文件保存天数

*/

public void autoClear(final int autoClearDay) {

FileUtil.delete(getGlobalpath(), new FilenameFilter() {

@Override

public boolean accept(File file, String filename) {

String s = FileUtil.getFileNameWithoutExtension(filename);

int day = autoClearDay < 0 ? autoClearDay : -1 * autoClearDay;

String date = "crash-" + DateUtil.getOtherDay(day);

return date.compareTo(s) >= 0;

}

});

}

}

在自己的Appcation类中初始化这个CrashHandler

import android.app.Application;

public class MyAppcation extends Application{

@Override

public void onCreate() {

super.onCreate();

CrashHandler.getInstance().init(this);

}

}

AndroidManifest.xml

d0b8700046e8?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=weixin

AndroidManifest.xml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值