package com.lfk.justweengine.utils.crashHandler; import android.annotation.SuppressLint; import android.app.AlarmManager; import android.app.Application; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.util.Log; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * CrashHandler * Solve thread crash * * @author liufengkai * Created by liufengkai on 16/1/16. */ public class CrashHandler implements Thread.UncaughtExceptionHandler { private static final String TAG = "CrashHandler"; private Application context; private HashMap<String, String> info; private DateFormat formatter; private static CrashHandler instance; private Thread.UncaughtExceptionHandler uncaughtExceptionHandler; // Restart activity private Class<?> Activity = null; private String ActivityName = null; private ArrayList<AfterCrashListener> listener; /** * get CrashHandler Instance * * @return CrashHandler */ public static CrashHandler getInstance() { if (instance == null) { instance = new CrashHandler(); } return instance; } public void setRestartActivity(Class<?> activity) { this.Activity = activity; } public void setActivityName(String activityName) { ActivityName = activityName; } /** * init * * @param context */ @SuppressLint("SimpleDateFormat") public void init(Application context) { this.context = context; uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); info = new HashMap<>(); listener = new ArrayList<>(); formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); CrashHandlerDefault.init(); } @Override public void uncaughtException(Thread thread, Throwable ex) { handleException(ex); uncaughtExceptionHandler .uncaughtException(thread, ex); } private boolean handleException(Throwable throwable) { if (throwable == null) return false; if (listener != null) { for (int i = 0; i < listener.size(); i++) { listener.get(i).AfterCrash(); } } collectDeviceInfo(context); writeCrashInfoToFile(throwable); if (Activity != null) restart(Activity); else if (ActivityName != null) { restart(ActivityName); } return true; } /** * Collect Device Info * * @param ctx context */ 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 + ""; info.put("versionName", versionName); info.put("versionCode", versionCode); info.put("crashTime", formatter.format(new Date())); } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "an error occurred when collect package info", e); } Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); info.put(field.getName(), field.get(null).toString()); Log.d(TAG, field.getName() + " : " + field.get(null)); } catch (Exception e) { Log.e(TAG, "an error occurred when collect crash info", e); } } } /** * Write crash info To File * * @param ex throwable message */ private void writeCrashInfoToFile(Throwable ex) { StringBuilder sb = new StringBuilder(); sb.append("crash log by JustWeEngine \n"); for (Map.Entry<String, String> entry : info.entrySet()) { sb.append(entry.getKey()) .append("---------->") .append(entry.getValue()) .append("\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); writeLog(sb.toString()); } /** * write log in file * * @param log log */ private void writeLog(String log) { File file = new File(CrashHandlerDefault.Log_Default_Path + "/" + formatter.format(new Date()) + ".log"); try { FileOutputStream fileOutputStream = new FileOutputStream(file); byte[] bytes = log.getBytes(); fileOutputStream.write(bytes); fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } /** * restart Activity * * @param activity classZ */ private void restart(Class<?> activity) { try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e(TAG, "error : ", e); } Intent intent = new Intent(context.getApplicationContext(), activity); restart(intent); } private void restart(String className) { try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e(TAG, "error : ", e); } Intent intent = new Intent(); intent.setClassName(context.getApplicationContext(), className); restart(intent); } private void restart(Intent intent) { PendingIntent restartIntent = PendingIntent.getActivity( context.getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_CLEAR_TASK); // 使用PendingIntent重启 AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); } public void addCrashListener(AfterCrashListener listener) { this.listener.add(listener); } }