[安卓开发基础]捕获崩溃日志方法

本文介绍了一个自定义的CrashHandler类,用于在Android应用中捕获未捕获的异常,记录详细的设备信息和异常堆栈,保存至本地文件,并通过Toast通知用户异常信息。实现了单例模式,确保了CrashHandler实例的唯一性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CrashHandler.java

package com.landicorp.android.factorytest;

import java.io.File;
import java.io.FileOutputStream;
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.SimpleDateFormat;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

public class CrashHandler implements UncaughtExceptionHandler {

public static final String CrashFilePath = "/sdcard/FTCrash.txt";
public static final int LogFileLimit = 10;

public static final String TAG = "CrashHandler";

//系统默认的UncaughtException处理类 
private Thread.UncaughtExceptionHandler mDefaultHandler;
//CrashHandler实例
private static CrashHandler mCrash= null;
//程序的Context对象
private Context mContext;
//用来存储设备信息和异常信息
private Map<String, String> infos = new HashMap<String, String>();

//用于格式化日期,作为日志文件名的一部分
private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
private Throwable mThrowable =null;
/** 保证只有一个CrashHandler实例 */
private CrashHandler() 
{
    
}

/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance() {
    
    if(mCrash==null)
    {
        mCrash = new CrashHandler();
    }
    return mCrash;
}

/**
 * 初始化
 * 
 * @param context
 */
public void init(Context context) {
    mContext = context;
    //获取系统默认的UncaughtException处理器
    mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    //设置该CrashHandler为程序的默认处理器
    Thread.setDefaultUncaughtExceptionHandler(this);
}

/**
 * 当UncaughtException发生时会转入该函数来处理
 */
@Override
public void uncaughtException(Thread thread, Throwable ex) 
{
    //保存异常日志到文件
    saveCrashInfo2File(ex);
    new Thread() 
    {
        @Override
        public void run() 
        {
            Looper.prepare();
            Toast.makeText(mContext, "很抱歉,程序出现异常\r\n日志保存在:"+CrashFilePath, Toast.LENGTH_LONG).show();
            Looper.loop(); 
        }
    }.start();

    try 
    {
        Thread.sleep(2000);
    } catch (Exception e) {
        // TODO: handle exception
    }
   
    android.os.Process.killProcess(android.os.Process.myPid());
    System.exit(1);
}


/**
 * 收集设备参数信息
 * @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 == null ? "null" : 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  返回文件名称,便于将文件传送到服务器
 */
private int saveCrashInfo2File(Throwable ex) {

    //将设备信息变成string
    StringBuffer sb = new StringBuffer();
    for (Map.Entry<String, String> entry : infos.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue();
        sb.append(key + "=" + value + "\n");
    }

    //递归获取全部的exception信息
    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.close();
    String result = writer.toString();
    sb.append(result); //将写入的结果

    try {
        File logFile=new File(CrashFilePath);
        if(logFile.exists())
        {
            logFile.delete();
            logFile.createNewFile();
        }
        FileOutputStream fout=new FileOutputStream(logFile,true);
        fout.write("\r\n".getBytes());
        fout.write(sb.toString().getBytes(), 0, sb.toString().length());
        fout.write("\r\n".getBytes());
        fout.close();
    } catch (Exception e) {
        // TODO: handle exception
    }
  
    return 1;
}

Comparator<File> newfileFinder = new Comparator<File>(){

    @Override
    public int compare(File x, File y) {
        // TODO Auto-generated method stub
        if (x.lastModified()>y.lastModified()) return 1;
        if (x.lastModified()<y.lastModified()) return -1;
        else return 0;
    }

};

}

使用方法:CrashHandler.getInstance().init(getApplicationContext());

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值