package com.shayu.phonelive; import android.app.Application; import android.content.Context; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.widget.Toast; import com.yunbao.common.utils.FileUtil; import com.yunbao.common.utils.SpUtil; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; /** * @ClassName NeverCrashUtils * @Description 全局捕获异常 */ public class NeverCrashUtils { private final static String TAG = NeverCrashUtils.class.getSimpleName(); private final static NeverCrashUtils INSTANCE = new NeverCrashUtils(); private boolean debugMode; private MainCrashHandler mainCrashHandler; private UncaughtCrashHandler uncaughtCrashHandler; private NeverCrashUtils() { } public static NeverCrashUtils getInstance() { return INSTANCE; } private synchronized MainCrashHandler getMainCrashHandler() { if (null == mainCrashHandler) { mainCrashHandler = (t, e) -> { }; } return mainCrashHandler; } /** * 主线程发生异常时的回调,可用于打印日志文件 *

* 注意跨线程操作的可能 */ public NeverCrashUtils setMainCrashHandler(MainCrashHandler mainCrashHandler) { this.mainCrashHandler = mainCrashHandler; return this; } private synchronized UncaughtCrashHandler getUncaughtCrashHandler() { if (null == uncaughtCrashHandler) { uncaughtCrashHandler = (t, e) -> { }; } return uncaughtCrashHandler; } /** * 子线程发生异常时的回调,可用于打印日志文件 *

* 注意跨线程操作的可能 */ public NeverCrashUtils setUncaughtCrashHandler(UncaughtCrashHandler uncaughtCrashHandler) { this.uncaughtCrashHandler = uncaughtCrashHandler; return this; } private boolean isDebugMode() { return debugMode; } /** * debug模式,会打印log日志,且toast提醒发生异常,反之则都没有 */ public NeverCrashUtils setDebugMode(boolean debugMode) { this.debugMode = debugMode; return this; } /** * 完成监听异常的注册 * @param application application */ public void register(Application application) { //主线程异常拦截 new Handler(Looper.getMainLooper()).post(() -> { while (true) { try { Looper.loop(); } catch (Throwable e) { if (isDebugMode()) { Log.e(TAG, "未捕获的主线程异常行为", e); } e.printStackTrace(); Toast.makeText(application, "发生闪退", Toast.LENGTH_SHORT).show(); FileUtil.saveStringToFile(new File(application.getDir("files", Context.MODE_PRIVATE).getAbsolutePath()),throwableToString(e),"error.log"); getMainCrashHandler().mainException(Looper.getMainLooper().getThread(), e); } } }); //子线程异常拦截 Thread.setDefaultUncaughtExceptionHandler((t, e) -> { if (isDebugMode()) { Log.e(TAG, "未捕获的子线程异常行为", e); } e.printStackTrace(); Toast.makeText(application, "发生闪退", Toast.LENGTH_SHORT).show(); FileUtil.saveStringToFile(new File(application.getDir("files", Context.MODE_PRIVATE).getAbsolutePath()),throwableToString(e),"error.log"); getMainCrashHandler().mainException(Looper.getMainLooper().getThread(), e); getUncaughtCrashHandler().uncaughtException(t, e); }); } public interface MainCrashHandler { void mainException(Thread t, Throwable e); } public interface UncaughtCrashHandler { void uncaughtException(Thread t, Throwable e); } private static String throwableToString(Throwable e) { StringWriter writer=new StringWriter(); writer.write("time="+System.currentTimeMillis()+"\n"); writer.write("AndroidVersion="+ Build.VERSION.SDK_INT+"\n"); writer.write("AndroidName="+ Build.VERSION.RELEASE+"\n"); writer.write("PhoneName="+ Build.BRAND+"\n"); writer.write("Phone="+ Build.MODEL+"\n"); writer.write("CPU="+ Arrays.toString(Build.SUPPORTED_ABIS) +"\n"); writer.write("UserData="+SpUtil.getInstance().getStringValue(SpUtil.USER_INFO)+"\n"); writer.write("[ERROR]"); PrintWriter printWriter=new PrintWriter(writer); e.printStackTrace(printWriter); return writer.toString(); } }