Android 全局异常捕获

该博客介绍了一个名为NeverCrashUtils的工具类,用于全局捕获和处理Android应用中的主线程和子线程异常。通过设置MainCrashHandler和UncaughtCrashHandler接口,可以在发生异常时进行定制的日志记录和反馈。在MyApplication中初始化并注册该工具类,可以根据debug模式打印日志并显示Toast提示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NeverCrashUtils工具类
import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

/**
 * @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;
    }

    /**
     * 主线程发生异常时的回调,可用于打印日志文件
     * <p>
     * 注意跨线程操作的可能
     */
    public NeverCrashUtils setMainCrashHandler(MainCrashHandler mainCrashHandler) {
        mainCrashHandler = mainCrashHandler;
        return this;
    }

    private synchronized UncaughtCrashHandler getUncaughtCrashHandler() {
        if (null == uncaughtCrashHandler) {
            uncaughtCrashHandler = (t, e) -> {
            };
        }
        return uncaughtCrashHandler;
    }

    /**
     * 子线程发生异常时的回调,可用于打印日志文件
     * <p>
     * 注意跨线程操作的可能
     */
    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);
                        new Handler(Looper.getMainLooper()).post(() ->
                                //Toast.makeText(application, "主线程发生异常,请查看控制台日志!\n此提醒和控制台打印仅在debug版本下有效!", Toast.LENGTH_LONG).show());
                        ToastUtils.getInstance(application).show("程序出小差了...",1000));
                    }
                    getMainCrashHandler().mainException(Looper.getMainLooper().getThread(), e);
                }
            }
        });

        //子线程异常拦截
        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
            if (isDebugMode()) {
                Log.e(TAG, "未捕获的子线程异常行为", e);
                new Handler(Looper.getMainLooper()).post(() ->
                        ToastUtils.getInstance(application).show("程序出小差了...",1000));
            }
            getUncaughtCrashHandler().uncaughtException(t, e);
        });
    }

    public interface MainCrashHandler {
        void mainException(Thread t, Throwable e);
    }

    public interface UncaughtCrashHandler {
        void uncaughtException(Thread t, Throwable e);
    }
}

MyApplication

import android.app.Application;
import android.content.Context;
import android.util.Log;
import com.test.project.BuildConfig;
import com.test.project.utils.NeverCrashUtils;
import me.jessyan.autosize.AutoSizeConfig;

/**
 * @ClassName MyApplication
 * @Description 全局
 */

public class MyApplication extends Application {

    private static final String TAG = "MyApplication";
    public static Context context;

    @Override
    public void onCreate() {
        super.onCreate();

        //禁止跟随系统改变文字大小
        AutoSizeConfig.getInstance().setExcludeFontScale(true);

        context = getApplicationContext();

        //全局异常捕获
        NeverCrashUtils.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);
    }

}

别忘记在ActivityManifest.xml中添加

<application
        android:name=".base.MyApplication"

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值