在Java or Android 开发中,会接触到各种Exception 先看一下分支结构:
顶级Throwable:
然后细分为Error(无法处理) 和Exception(可以处理)的分支
接触到最多的异常安装频率来说有这么几种:
NullPorinterException 空指针 访问的对象或者方法等为Null
ArrayIndexOutOfBoundsException 数组角标越界 比如size = 5 ,get(8),[8]
NumberFormatException 转换异常 比如 数据 "123a",通过Integer.valueOf()
ParseException 解析异常
ClassCastException 类型转换异常
ArithmeticException 算术异常 比如1/0
一旦异常发生就会发生不可期的后果,比如数据错误,程序崩溃,在Android中 如果异常存在,没有捕获可能APP直接就崩溃了 停止运行,用户体验极其不友好
怎么去处理比较优雅呢?
主角登场:---> Thread.UncaughtExceptionHandler
通过源码可以看出这是个接口 需要实现它
然后 它有个方法需要实现:
void uncaughtException(Thread t, Throwable e);
t代表线程,当前的线程 e是异常的一些信息
那么如何在Android中进行应用呢?
首先封装个管理类,做成单例模式,通过init 加载
private CarshHandlerMessage()
{
}
public static CarshHandlerMessage getInstance()
{
return sInstance;
}
public void init(Context context)
{
mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
mContext = context.getApplicationContext();
intent = new Intent(mContext,CarshCauseActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
这里用的是饿汉式,不过更推荐懒汉式写法 然后加同步
然后在实现的方法里写上回调和业务逻辑
@Override
public void uncaughtException(Thread t, Throwable e)
{
try
{
//保存到本地
exportExceptionToSDCard(e);
//下面也可以写上传的服务器的代码
} catch (Exception e1)
{
e1.printStackTrace();
}
e.printStackTrace();
//如果系统提供了默认的异常处理器,则交给系统去结束程序,否则就自己结束自己
if (mDefaultCrashHandler != null)
{
mDefaultCrashHandler.uncaughtException(t, e);
}
}
完整代码:
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import com.example.qualityManagement.CarshCauseActivity;
import com.example.suppliermanagement.util.GlobalVar;
import com.google.gson.Gson;
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;
public class CarshHandlerMessage implements Thread.UncaughtExceptionHandler
{
private static final String PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
private static final String FILE_NAME_SUFFIX = ".trace";
private static CarshHandlerMessage sInstance = new CarshHandlerMessage();
private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
private Context mContext;
private Object sb;
private Intent intent;
private CarshHandlerMessage()
{
}
public static CarshHandlerMessage getInstance()
{
return sInstance;
}
public void init(Context context)
{
mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
mContext = context.getApplicationContext();
intent = new Intent(mContext,CarshCauseActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
/**
* 当程序中有未被捕获的异常,系统将会调用这个方法
*
* @param t 出现未捕获异常的线程
* @param e 得到异常信息
*/
@Override
public void uncaughtException(Thread t, Throwable e)
{
try
{
//保存服务器
exportExceptionToSDCard(e);
} catch (Exception e1)
{
e1.printStackTrace();
}
e.printStackTrace();
//如果系统提供了默认的异常处理器,则交给系统去结束程序,否则就自己结束自己
if (mDefaultCrashHandler != null)
{
mDefaultCrashHandler.uncaughtException(t, e);
}
}
/**
* 获取e.printStackTrace() 的具体信息,赋值给String 变量,并返回
*
* @param e
* Exception
* @return e.printStackTrace() 中 的信息
*/
public static String getStackTraceInfo(Throwable e) {
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
e.printStackTrace(pw);//将出错的栈信息输出到printWriter中
pw.flush();
sw.flush();
return sw.toString();
} catch (Exception ex) {
return "printStackTrace()转换错误";
} finally {
if (sw != null) {
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (pw != null) {
pw.close();
}
}
}
/**
* 导出异常信息提交
*
* @param e
*/
private void exportExceptionToSDCard( final Throwable e)
{
new Thread(new Runnable() {
@Override
public void run() {
try {
DeciveInfo info = appendPhoneInfo();
StringBuilder stb = new StringBuilder();
for(int x = 0 ; x < e.getStackTrace().length;x++){
stb.append(e.getStackTrace()[x]).append("\n");
}
stb.append(e.getMessage());
stb.append(getStackTraceInfo(e));
info.setErrMessage(stb.toString());
String json = new Gson().toJson(info);
String path = url;
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("msg", json);
connection.setRequestMethod("POST");
connection.setConnectTimeout(60000);
connection.setReadTimeout(60000);
connection.connect();
if(connection.getResponseCode() == 200){
connection.getInputStream();
mContext.startActivity(intent);
}
} catch (NameNotFoundException e1) {
e1.printStackTrace();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}).start();
}
/**
* 获取手机信息
*/
private DeciveInfo appendPhoneInfo() throws PackageManager.NameNotFoundException
{
PackageManager pm = mContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
DeciveInfo info = new DeciveInfo();
info.setVersionCode(String.valueOf(pi.versionCode));
info.setVersionName(pi.versionName);
info.setAndroidVersion(String.valueOf(Build.VERSION.SDK_INT));
info.setInfo(Build.MANUFACTURER + "\n"+Build.MODEL + "\n");
return info;
}
public static class DeciveInfo {
private String versionCode;
private String versionName;
private String date;
private String errMessage;
private String androidVersion;
private String info;
private String threadName;
public String getThreadName() {
return threadName;
}
public void setThreadName(String threadName) {
this.threadName = threadName;
}
public String getVersionCode() {
return versionCode;
}
public void setVersionCode(String versionCode) {
this.versionCode = versionCode;
}
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getErrMessage() {
return errMessage;
}
public void setErrMessage(String errMessage) {
this.errMessage = errMessage;
}
public String getAndroidVersion() {
return androidVersion;
}
public void setAndroidVersion(String androidVersion) {
this.androidVersion = androidVersion;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
}
注意:
android 9.0上传信息需要加入网络动态权限
https://blog.csdn.net/qq_29769851/article/details/105663758