package com.example.qingyangdemo.base; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.lang.Thread.UncaughtExceptionHandler; import java.net.ConnectException; import java.net.SocketException; import java.net.UnknownHostException; import org.apache.http.HttpException; import com.example.qingyangdemo.R; import com.example.qingyangdemo.common.FileUtil; import com.example.qingyangdemo.common.UIHelper; import com.example.qingyangdemo.net.Constant; import android.content.Context; import android.content.pm.PackageInfo; import android.os.Build; import android.os.Looper; import android.widget.Toast; /** * 应用程序异常类:用于捕获异常和提示错误信息 * * @author 赵庆洋 * */ public class AppException extends Exception implements UncaughtExceptionHandler { public final static String LOG_TAG = "qingyang_log"; // 错误异常类型 public final static byte TYPE_NETWORK = 0x01; public final static byte TYPE_SOCKET = 0x02; public final static byte TYPE_HTTP_CODE = 0x03; public final static byte TYPE_HTTP_ERROR = 0x04; public final static byte TYPE_XML = 0x05; public final static byte TYPE_IO = 0x06; public final static byte TYPE_RUN = 0x07; private byte type; private int code; // 系统默认的UncaughtExceptionHandler处理类 private UncaughtExceptionHandler mDefaultHandler; private AppException() { this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); } private AppException(byte type, int code, Exception excp) { super(excp); this.type = type; this.code = code; this.saveErrorLog(excp); } /** * 获取APP异常崩溃处理对象 * * @param context * @return */ public static AppException getAppExceptionHandler() { return new AppException(); } /** * 友好的错误提示 * * @param context */ public void makeToast(Context context) { switch (this.getType()) { case TYPE_HTTP_CODE: String err = context.getString(R.string.http_status_code_error, this.getCode()); Toast.makeText(context, err, Toast.LENGTH_SHORT).show(); break; case TYPE_HTTP_ERROR: Toast.makeText(context, context.getString(R.string.http_exception_error), Toast.LENGTH_SHORT).show(); case TYPE_SOCKET: Toast.makeText(context, context.getString(R.string.socket_exception_error), Toast.LENGTH_SHORT).show(); break; case TYPE_NETWORK: Toast.makeText(context, context.getString(R.string.network_not_connected), Toast.LENGTH_SHORT).show(); break; case TYPE_XML: Toast.makeText(context, context.getString(R.string.xml_parser_failed), Toast.LENGTH_SHORT).show(); break; case TYPE_IO: Toast.makeText(context, context.getString(R.string.io_exception_error), Toast.LENGTH_SHORT).show(); break; case TYPE_RUN: Toast.makeText(context, context.getString(R.string.app_run_code_error), Toast.LENGTH_SHORT).show(); break; default: break; } } /** * 保存错误日志 * * @param excp */ public void saveErrorLog(Exception excp) { String errorlog = Constant.LOG_NAME; String logFilePath = ""; FileWriter fw = null; PrintWriter pw = null; try { logFilePath = FileUtil.fileDirectory(Constant.LOG_PATH, errorlog); // 没有挂载SD卡,无法写文件 if (logFilePath.equals("")) { return; } File logFile = new File(logFilePath); if (!logFile.exists()) { logFile.createNewFile(); } fw = new FileWriter(logFile, true); pw = new PrintWriter(fw); excp.printStackTrace(pw); pw.close(); fw.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (pw != null) { pw.close(); } if (fw != null) { try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public void uncaughtException(Thread thread, Throwable ex) { // TODO // 异常捕获处理 if (!handleException(ex) && mDefaultHandler != null) { mDefaultHandler.uncaughtException(thread, ex); } } public static AppException http(int code) { return new AppException(TYPE_HTTP_CODE, code, null); } public static AppException http(Exception e) { return new AppException(TYPE_HTTP_ERROR, 0, e); } public static AppException socket(Exception e) { return new AppException(TYPE_SOCKET, 0, e); } public static AppException io(Exception e) { if (e instanceof UnknownHostException || e instanceof ConnectException) { return new AppException(TYPE_NETWORK, 0, e); } else if (e instanceof IOException) { return new AppException(TYPE_IO, 0, e); } return run(e); } public static AppException network(Exception e) { if (e instanceof UnknownHostException || e instanceof ConnectException) { return new AppException(TYPE_NETWORK, 0, e); } else if (e instanceof HttpException) { return http(e); } else if (e instanceof SocketException) { return socket(e); } return http(e); } public static AppException xml(Exception e) { return new AppException(TYPE_XML, 0, e); } public static AppException run(Exception e) { return new AppException(TYPE_RUN, 0, e); } public byte getType() { return type; } public int getCode() { return code; } /** * 自定义异常处理:收集错误信息并发送错误报告 * * @param ex * @return 处理异常返回true否则返回false */ private boolean handleException(Throwable ex) { if (ex == null) { return false; } final Context context = AppManager.getAppManager().currentActivity(); if (context == null) { return false; } final String crashReport = getCrashReport(context, ex); // 保存错误日志 saveErrorLog((Exception) ex); new Thread(new Runnable() { @Override public void run() { Looper.prepare(); UIHelper.sendAppCrashReport(context, crashReport); Looper.loop(); } }).start(); return true; } /** * 获取app崩溃异常报告 * * @param context * @param ex * @return */ private String getCrashReport(Context context, Throwable ex) { PackageInfo packageInfo = ((BaseApplication) context .getApplicationContext()).getPackageInfo(); StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("Version: " + packageInfo.versionName + "(" + packageInfo.versionCode + ")\n"); stringBuffer.append("Android: " + Build.VERSION.RELEASE + "(" + Build.MODEL + ")\n"); stringBuffer.append("Exception: " + ex.getMessage() + "\n"); // 异常元素集合 StackTraceElement[] elements = ex.getStackTrace(); for (int i = 0; i < elements.length; i++) { stringBuffer.append(elements[i].toString() + "\n"); } return stringBuffer.toString(); } }