Today, he said, as the program of apes that we encounter every day things bug, the bug is not terrible terrible is the stack information when not out of the bug, so it is very important for bug information collection, generally with the third party can easily collect bugly or their Allies and so on, but the company does not make use of third-party, and android just has a vision of the native Often UncaughtExceptionHandler collection class, so today’s blog is begin from this class.
UncaughtExceptionHandler is known by name, that is, it is to handle the exception that we did not catch, the specific use of two steps 1. Implement our own exception handling class
public class CrashHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
}
}Copy the code
We need to realize Thread. UncaughtExceptionHandler interface when an uncaught exception will callback uncaughtException (Thread Thread, Throwable ex) method
2. Set the CrashHandler to the default value
Thread.setDefaultUncaughtExceptionHandler(crashHandler);Copy the code
The above is just an introduction to the usage steps. I will directly paste the code to initialize the specific project in application
package com.zly.www.basedemo.base;
import android.app.Application;
import android.content.Context;
import com.zly.www.basedemo.exception.CrashHandler;
/**
* Created by zly on 2016/6/11.
*/
public class AppApplication extends Application {
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
this.mContext = this;
CrashHandler.getInstance().init(this);
}
public static Context getContext(){
return mContext;
}
}
Copy the code
The CrashHandler implementation class is as follows
package com.zly.www.basedemo.exception; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.Environment; import android.os.Looper; import android.util.Log; import android.widget.Toast; import com.zly.www.basedemo.utils.AppManager; import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; / * * * * global exception handling Created by zly on 2016/7/3. * / public class CrashHandler implements Thread. UncaughtExceptionHandler {/ * * * system default UncaughtExceptionHandler * / private Thread. UncaughtExceptionHandler mDefaultHandler; /** * context */ private Context mContext; / / private Map paramsMap = new HashMap<>(); Private SimpleDateFormat format = new SimpleDateFormat(" YYYY-MM-DD-HH-MM-SS "); private SimpleDateFormat = new SimpleDateFormat(" YYYY-MM-DD-HH-MM-SS "); private String TAG = this.getClass().getSimpleName(); private static CrashHandler mInstance; Private synchronized CrashHandler() {} public static synchronized CrashHandler getInstance(){if(null == mInstance){ mInstance = new CrashHandler(); } return mInstance; } public void init(Context context){ mContext = context; mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); } /** * Override public void uncaughtException(Thread Thread, Throwable ex) {if(! handleException(ex) && mDefaultHandler ! = null){ mDefaultHandler.uncaughtException(thread,ex); }else{ try { Thread.sleep(3000); } catch (InterruptedException e) { Log.e(TAG, "error : ", e); } AppManager.getAppManager().AppExit(mContext); }} /** * Collect error information. */ private Boolean handleException(Throwable ex) {if (ex == null) {return false; } collectDeviceInfo(mContext); addCustomInfo(); new Thread() { @Override public void run() { Looper.prepare(); Toast.makeText(mContext, "Application is distracted..." , Toast.LENGTH_SHORT).show(); Looper.loop(); } }.start(); saveCrashInfo2File(ex); return true; } /** * Collect device parameters * @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 + ""; paramsMap.put("versionName", versionName); paramsMap.put("versionCode", versionCode); } } catch (PackageManager.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); paramsMap.put(field.getName(), field.get(null).toString()); } catch (Exception e) { Log.e(TAG, "an error occured when collect crash info", e); }} /** * Add custom parameters */ private void addCustomInfo() {} /** * Save error information to a file ** @param ex * @return Returns the name of the file to facilitate transferring the file to the server */ private String saveCrashInfo2File(Throwable ex) { StringBuffer sb = new StringBuffer(); for (Map.Entry entry : paramsMap.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\n"); } 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 { long timestamp = System.currentTimeMillis(); String time = format.format(new Date()); String fileName = "crash-" + time + "-" + timestamp + ".log"; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crash/"; File dir = new File(path); if (! dir.exists()) { dir.mkdirs(); } FileOutputStream fos = new FileOutputStream(path + fileName); fos.write(sb.toString().getBytes()); fos.close(); } return fileName; } catch (Exception e) { Log.e(TAG, "an error occured while writing file..." , e); } return null; }}Copy the code
The code here is a little bit simpler and the only thing to notice is that I’m not using the usual one to exit the app
android.os.Process.killProcess(android.os.Process.myPid())
System.exit(1)Copy the code
Because I found that the test process of 4.4 or above system using this method to kill the app will restart, similar memory app hanging system to broadcast to draw up the app that (thanks to his brother for help to find out why ^_^ here), then it is likely to cause an exception report situation many times, so here I use their implementation of the act Ivity stack to manage exit.
The activity management class
package com.zly.www.basedemo.utils;
import java.util.Stack;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
/**
* Activity管理类:用于管理Activity和退出程序
* Created by zly on 2016/6/11.
*/
public class AppManager {
private static Stack activityStack;
private static AppManager instance;
private AppManager() {
}
/**
* 单一实例
*/
public static AppManager getAppManager() {
if (instance == null) {
instance = new AppManager();
}
return instance;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
if (activityStack == null) {
activityStack = new Stack();
}
activityStack.add(activity);
}
/**
* 获取当前Activity(堆栈中最后一个压入的)
*/
public Activity currentActivity() {
Activity activity = activityStack.lastElement();
return activity;
}
/**
* 结束当前Activity(堆栈中最后一个压入的)
*/
public void finishActivity() {
Activity activity = activityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity) {
if (activity != null) {
activityStack.remove(activity);
activity.finish();
activity = null;
}
}
/**
* 结束指定类名的Activity
*/
public void finishActivity(Class cls) {
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
finishActivity(activity);
break;
}
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (int i = 0; i < activityStack.size(); i++) {
if (null != activityStack.get(i)) {
activityStack.get(i).finish();
}
}
activityStack.clear();
}
/**
* 退出应用程序
*/
public void AppExit(Context context) {
try {
finishAllActivity();
ActivityManager activityMgr = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
activityMgr.killBackgroundProcesses(context.getPackageName());
System.exit(0);
} catch (Exception e) {
}
}
} Copy the code
If you have any questions, please leave a message ~~