程序出错开发者应该尽量避免。可设备种类数不胜数,如果出现了错误我们就应该正确收集出现错误异常的相关信息,
下面是本人在开发时写的一种收集方法。
先在Compontent包下创建CrashHandler.java并实现Thread.UncaughtExceptionHandler。
Thread.UncaughtExceptionHandler:线程未捕获异常处理器,用来处理未捕获异常。如果程序出现了未捕获异常,默认会弹出系统中强制关闭对话框。我们需要实现此接口,并注册为程序中默认未捕获异常处理。这样当未捕获异常发生时,就可以做一些个性化的异常处理操作。
CrashHandler.java 代码如下(详情看注释):
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import com.example.chen.news2.app.App;
import com.example.chen.news2.util.LogUtil;
import com.example.chen.news2.util.ToastUtil;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
/**
* Created by chen on 2017/7/21.
*/
/*
* 全局处理异常
* */
public class CrashHandler implements Thread.UncaughtExceptionHandler{
public static Thread.UncaughtExceptionHandler defaultHandler = null;
private Context context = null;
public final String TAG = CrashHandler.class.getSimpleName();
public CrashHandler(Context context){
this.context = context;
}
/*
* 初始化
* 设置该CrashHander为程序的默认处理器
* */
public static void init(CrashHandler crashHandler){
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(crashHandler);
}
/*
* 未处理异常
* */
@Override
public void uncaughtException(Thread thread, Throwable ex) {
System.out.println(ex.toString());
LogUtil.e(TAG, ex.toString());
LogUtil.e(TAG, collectCrashDeviceInfo());
LogUtil.e(TAG, getCrashInfo(ex));
//调用系统错误机制
defaultHandler.uncaughtException(thread,ex);
ToastUtil.shortShow("抱歉,程序发生异常即将退出");
App.getInstance().exitApp();
}
/*
* 得到程序崩溃的详细信息
* */
private String getCrashInfo(Throwable ex) {
Writer result = new StringWriter();
PrintWriter printWriter = new PrintWriter(result);
ex.setStackTrace(ex.getStackTrace());
ex.printStackTrace(printWriter);
return result.toString();
}
/*
* 收集程序崩溃的设备信息*/
private String collectCrashDeviceInfo() {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(),PackageManager.GET_ACTIVITIES);
String VersionName = packageInfo.versionName;
String model = Build.MODEL;
String androidVersion = Build.VERSION.RELEASE;
String manufacturer = Build.MANUFACTURER;
return VersionName + " " + model+ " " + androidVersion + " " + manufacturer;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
因为是MVP的结构我们还要写两个工具类,在util包下创建ToastUtil.java和LogUtil.java两个文件。前面是定义一个通知,告诉用户程序出了问题;后面是获取日志,方便反馈和开发者获得具体的错误情况。
ToastUtil.java 代码如下:
package com.example.chen.news2.util;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.example.chen.news2.R;
import com.example.chen.news2.app.App;
/**
* Created by chen on 2017/7/21.
*/
public class ToastUtil {
static ToastUtil td;
public static void show(int resId) {
show(App.getInstance().getString(resId));
}
public static void show(String msg) {
if (td == null) {
td = new ToastUtil(App.getInstance());
}
td.setText(msg);
td.create().show();
}
public static void shortShow(String msg) {
if (td == null) {
td = new ToastUtil(App.getInstance());
}
td.setText(msg);
td.createShort().show();
}
Context context;
Toast toast;
String msg;
public ToastUtil(Context context) {
this.context = context;
}
public Toast create() {
View contentView = View.inflate(context, R.layout.dialog_toast, null);
TextView tvMsg = (TextView) contentView.findViewById(R.id.tv_toast_msg);
toast = new Toast(context);
toast.setView(contentView);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(Toast.LENGTH_LONG);
tvMsg.setText(msg);
return toast;
}
public Toast createShort() {
View contentView = View.inflate(context, R.layout.dialog_toast, null);
TextView tvMsg = (TextView) contentView.findViewById(R.id.tv_toast_msg);
toast = new Toast(context);
toast.setView(contentView);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(Toast.LENGTH_SHORT);
tvMsg.setText(msg);
return toast;
}
public void show() {
if (toast != null) {
toast.show();
}
}
public void setText(String text) {
msg = text;
}
}
LogUtil.java 代码如下:
package com.example.chen.news2.util;
import com.orhanobut.logger.BuildConfig;
import com.orhanobut.logger.Logger;
/**
* Created by chen on 2017/7/21.
*/
public class LogUtil {
public static boolean isDebug = BuildConfig.DEBUG;
private static final String TAG = "com.example.chen.news2";
public static void e(String tag, Object o) {
if(isDebug) {
Logger.e(tag, o);
}
}
public static void e(Object o) {
LogUtil.e(TAG,o);
}
public static void w(String tag, Object o) {
if(isDebug) {
Logger.w(tag, o);
}
}
public static void w(Object o) {
LogUtil.w(TAG,o);
}
public static void d(String msg) {
if(isDebug) {
Logger.d(msg);
}
}
public static void i(String msg) {
if(isDebug) {
Logger.i(msg);
}
}
}
最后还要在App包下App.java中初始化:
//初始化日志
Logger.init(getPackageName()).hideThreadInfo();
//初始化错误收集
CrashHandler.init(new CrashHandler(getApplicationContext()));
并且退出程序:
public void exitApp() {
if (allActivities != null) {
synchronized (allActivities) {
for (Activity act : allActivities) {
act.finish();
}
}
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
这是我的项目目录: