前段时间又温习了下Java,发现了一只野生的UncaughtExceptionHandler,以前居然没发现
从JDK1.5版本开始,加强了对线程的异常处理,如果线程没有捕获异常,那么Java虚拟机会寻找相关的UncaughtExceptionHandler实例,如果找到就调用它的uncaughtException(Thread t, Throwable e)方法。
在Thread类中提供了一个公共的静态的UncaughtExceptionHandler内部接口,负责处理线程未捕获的异常,它的唯一方法是uncaughtException(Thread t, Throwable e),t表示抛出异常的线程,e表示具体的异常。
Thread类提供两个设置异常处理类的方法:
setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler e)
第一个方法是静态方法,设置线程类的默认异常处理器,第二个是实例方法,设置线程实例的当前异常处理器;
Android中如果要把日志写到SD卡中记得加android.permission.WRITE_EXTERNAL_STORAGE权限
要在application里初始化
CrashHandler handler = CrashHandler.getInstance();
handler.init(this);
代码:
package com.peak.excatch;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
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.Environment;
import android.util.Log;
public class CrashHandler implements UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
private static final boolean DEBUG = true;
private static final String PATH = Environment.getExternalStorageDirectory().getPath()+"/exceptionCatch/log/";
private static final String FILE_NAME = "catch";
private static final String FLIE_NAME_SUFFIX = ".log";
private UncaughtExceptionHandler mDefaultCrashHandler;
private Context mContext;
public CrashHandler() {
}
/**
* 静态内部类单例
* @return
*/
public static CrashHandler getInstance(){
Log.d(TAG, "get crash instance.");
return InstanceHolder.sInstance;
}
private static class InstanceHolder{
private static CrashHandler sInstance = new CrashHandler();
}
public void init(Context context){
Log.d(TAG, "init UncaughtExceptionnHandler");
mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
mContext = context.getApplicationContext();
}
/**
* 程序崩溃会调用该方法
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
try{
Log.d(TAG, "uncaughtException ...");
dumpExceptionToSDCard(ex);
// uploadExceptionToServer(ex); 需要把异常上传到服务器,编写逻辑 解除该行注释
}catch(IOException e){
e.printStackTrace();
}
}
private void dumpExceptionToSDCard(final Throwable ex) throws IOException{
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
if(DEBUG){
Log.w(TAG, "sdcard unmounted,skip dump exception");
return;
}
}
File dir = new File(PATH);
if(!dir.exists()){
Log.d(TAG, "log dir not exists. ready create");
dir.mkdirs();
}
long current = System.currentTimeMillis();
final String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current));
final File file = new File(PATH + FILE_NAME + FLIE_NAME_SUFFIX);
new Thread(new Runnable() {
@Override
public void run() {
try{
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
pw.println(time);
dumpPhoneInfo(pw,ex);
pw.close();
}catch(Exception e){
Log.e(TAG, "dump crash info failed : " + Log.getStackTraceString(e));
}
}
}).start();
}
private void dumpPhoneInfo(PrintWriter pw, Throwable ex)throws NameNotFoundException {
Log.d(TAG, "dumpPhoneInfo ... start");
PackageManager pm = mContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),PackageManager.GET_ACTIVITIES);
pw.print("App version: ");
pw.print(pi.versionName);
pw.print('_');
pw.println(pi.versionCode);
//Android版本号
pw.print("OS Version: ");
pw.print(Build.VERSION.RELEASE);
pw.print(" _ sdk: ");
pw.println(Build.VERSION.SDK_INT);
//手机制造商
pw.print("Vendor: ");
pw.println(Build.MANUFACTURER);
//手机型号
pw.print("Model: ");
pw.println(Build.MODEL);
//CPU架构
pw.print("CPU ABI : ");
pw.println(Build.CPU_ABI);
pw.println();
//异常信息
ex.printStackTrace(pw);
}
private void uploadExceptionToServer(Throwable ex){
//上传到服务器逻辑代码
}
}