Android 捕获全局异常CrashHandler,防止异常闪退,记录异常日志
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 捕获全局异常CrashHandler,防止异常闪退,记录异常日志相关的知识,希望对你有一定的参考价值。
参考技术A import android.content.Context;import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* UncaughtException handler class
*
*/
public class CrashHandler implements UncaughtExceptionHandler
public static final String TAG = "CrashHandler";
public static final String PROGRAM_BROKEN_ACTION = "com.teligen.wccp.PROGRAM_BROKEN";
private UncaughtExceptionHandler mDefaultHandler;
private static CrashHandler instance = new CrashHandler();
private Context mContext;
private Class<?> mainActivityClass;
private Map<String, String> infos = new HashMap<String, String>();
private CrashHandler()
public static CrashHandler getInstance()
return instance;
public void init(Context context, Class<?> activityClass)
mContext = context;
this.setMainActivityClass(activityClass);
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
@Override
public void uncaughtException(Thread thread, Throwable ex)
if (!handleException(ex) && mDefaultHandler != null)
mDefaultHandler.uncaughtException(thread, ex);
else
System.out.println("uncaughtException--->" + ex.getMessage());
// Log.e(TAG, ex.getMessage());
logError(ex);
try
Thread.sleep(3000);
catch (InterruptedException e)
// Log.e("debug", "error:", e);
exitApp();
private boolean handleException(Throwable ex)
if (ex == null)
return false;
new Thread(new Runnable()
@Override
public void run()
Looper.prepare();
Toast.makeText(mContext.getApplicationContext(),
"unknown exception and exiting...Please checking logs in sd card!", Toast.LENGTH_LONG).show();
Looper.loop();
).start();
collectDeviceInfo(mContext.getApplicationContext());
logError(ex);
return true;
private void exitApp()
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
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 + "";
infos.put("versionName", versionName);
infos.put("versionCode", versionCode);
catch (NameNotFoundException e)
e.printStackTrace();
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields)
try
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
catch (Exception e)
private void logError(Throwable ex)
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : infos.entrySet())
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + "=" + value + "\n");
int num = ex.getStackTrace().length;
for (int i=0;i<num;i++)
sb.append(ex.getStackTrace()[i].toString());
sb.append("\n");
File file = new File(filePath+"/log.txt");
FileOutputStream fos = null;
try
fos = new FileOutputStream(file);
fos.write((sb.toString()+"exception:"+ex.getLocalizedMessage()).getBytes());
catch (FileNotFoundException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
finally
try
fos.close();
catch (IOException e)
e.printStackTrace();
public Class<?> getMainActivityClass()
return mainActivityClass;
public void setMainActivityClass(Class<?> mainActivityClass)
this.mainActivityClass = mainActivityClass;
filePath是记录日志的路径
在Applicaton中初始化
@Override
public void onCreate()
super.onCreate();
CrashHandler mCrashHandler = CrashHandler.getInstance();
mCrashHandler.init(getApplicationContext(), getClass());
initFile();
android 全局异常捕获,防止崩溃发生
主类
/**
* 用途:全局异常拦截
* <p>
* 作者:mjSoftKing
*/
public class NeverCrash
private final static String TAG = NeverCrash.class.getSimpleName();
private final static NeverCrash INSTANCE = new NeverCrash();
private boolean debugMode;
private MainCrashHandler mainCrashHandler;
private UncaughtCrashHandler uncaughtCrashHandler;
private NeverCrash()
public static NeverCrash getInstance()
return INSTANCE;
private synchronized MainCrashHandler getMainCrashHandler()
if (null == mainCrashHandler)
mainCrashHandler = (t, e) ->
;
return mainCrashHandler;
/**
* 主线程发生异常时的回调,可用于打印日志文件
* <p>
* 注意跨线程操作的可能
*/
public NeverCrash setMainCrashHandler(MainCrashHandler mainCrashHandler)
this.mainCrashHandler = mainCrashHandler;
return this;
private synchronized UncaughtCrashHandler getUncaughtCrashHandler()
if (null == uncaughtCrashHandler)
uncaughtCrashHandler = (t, e) ->
;
return uncaughtCrashHandler;
/**
* 子线程发生异常时的回调,可用于打印日志文件
* <p>
* 注意跨线程操作的可能
*/
public NeverCrash setUncaughtCrashHandler(UncaughtCrashHandler uncaughtCrashHandler)
this.uncaughtCrashHandler = uncaughtCrashHandler;
return this;
private boolean isDebugMode()
return debugMode;
/**
* debug模式,会打印log日志,且toast提醒发生异常,反之则都没有
*/
public NeverCrash 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);
new Handler(Looper.getMainLooper()).post(() ->
Toast.makeText(application, "主线程发生异常,请查看控制台日志!\\n此提醒和控制台打印仅在debug版本下有效!", Toast.LENGTH_LONG).show());
getMainCrashHandler().mainException(Looper.getMainLooper().getThread(), e);
);
//子线程异常拦截
Thread.setDefaultUncaughtExceptionHandler((t, e) ->
if (isDebugMode())
Log.e(TAG, "未捕获的子线程异常行为", e);
new Handler(Looper.getMainLooper()).post(() ->
Toast.makeText(application, "子线程发生异常,请查看控制台日志!\\n此提醒和控制台打印仅在debug版本下有效!", Toast.LENGTH_LONG).show());
getUncaughtCrashHandler().uncaughtException(t, e);
);
public interface MainCrashHandler
void mainException(Thread t, Throwable e);
public interface UncaughtCrashHandler
void uncaughtException(Thread t, Throwable e);
application下使用
/**
* 用途:
* <p>
* 作者:mjSoftKing
* 时间:2021/04/26
*/
public class App extends Application
private final static String TAG = App.class.getSimpleName();
@Override
public void onCreate()
super.onCreate();
NeverCrash.getInstance()
.setDebugMode(BuildConfig.DEBUG)
.setMainCrashHandler((t, e) ->
//todo 跨线程操作时注意线程调度回主线程操作
Log.e(TAG, "主线程异常");//此处log只是展示,当debug为true时,主类内部log会打印异常信息
//todo 此处做你的日志记录即可
)
.setUncaughtCrashHandler((t, e) ->
//todo 跨线程操作时注意线程调度回主线程操作
Log.e(TAG, "子线程异常");//此处log只是展示,当debug为true时,主类内部log会打印异常信息
//todo 此处做你的日志记录即可
)
.register(this);
最后别忘了注册application类
<manifest ...>
<application
android:name=".App"
...>
...
</application>
</manifest>
以上是关于Android 捕获全局异常CrashHandler,防止异常闪退,记录异常日志的主要内容,如果未能解决你的问题,请参考以下文章
Android设置全局异常捕获在baseActivity注册,才能捕获所有的activity的异常
Kotlin 协程协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )