Android源码剖析:基于 Handler、Looper 实现拦截全局崩溃、监控ANR等

相信很多人都会有一个疑问,我们为何要去阅读源码,工作上又用不上,这个问题很棒,我们就先从使用出发,然后分析这些用法的实现原理,这样才能体现出阅读源码的意义。

  1. 基于 Handler 和 Looper 拦截全局崩溃(主线程),避免 APP 退出。
  2. 基于 Handler 和 Looper 实现 ANR 监控。
  3. 基于 Handler 实现单线程的线程池。

实现代码

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        var startWorkTimeMillis = 0L
        Looper.getMainLooper().setMessageLogging {
            if (it.startsWith(">>>>> Dispatching to Handler")) {
                startWorkTimeMillis = System.currentTimeMillis()
            } else if (it.startsWith("<<<<< Finished to Handler")) {
                val duration = System.currentTimeMillis() - startWorkTimeMillis
                if (duration > 100) {
                    Log.e("主线程执行耗时过长","$duration 毫秒,$it")
                }
            }
        }
        val handler = Handler(Looper.getMainLooper())
        handler.post {
            while (true) {
                try {
                    Looper.loop()
                } catch (e: Throwable) {
                    // TODO 主线程崩溃,自行上报崩溃信息
                    if (e.message != null && e.message!!.startsWith("Unable to start activity")) {
                        android.os.Process.killProcess(android.os.Process.myPid())
                        break
                    }
                    e.printStackTrace()
                }
            }
        }
        Thread.setDefaultUncaughtExceptionHandler { thread, e ->
            e.printStackTrace()
            // TODO 异步线程崩溃,自行上报崩溃信息
        }
    }
}

通过上面的代码就可以就可以实现拦截UI线程的崩溃,耗时性能监控。但是也并不能够拦截所有的异常,如果在Activity的onCreate出现崩溃,导致Activity创建失败,那么就会显示黑屏。

ANR获取堆栈信息《Android:基于 Handler、Looper 实现 ANR 监控,获取堆栈

源码剖析

通过上面简单的代码,我们就实现崩溃和ANR的拦截和监控,但是我们可能并不知道是为何实现的,包括我们知道出现了ANR,但是我们还需要进一步分析为何处出现ANR,如何解决。今天分析的问题有:

  1. 如何拦截全局崩溃,避免APP退出。
  2. 如何实现 ANR 监控。
  3. 利用 Handler 实现单线程池功能。
  4. Activity 的生命周期为什么用 Handler 发送执行。
  5. Handler 的延迟操作如何实现。

涉及的源码

/java/android/os/Handler.java
/java/android/os/MessageQueue.java
/java/android/os/Looper.java
/java/android.app/ActivityThread.java

我们先从APP启动开始分析,APP的启动方法是在ActivityThread中,在main方法中创建了主线程的Looper,也就是当前进程创建。并且在main方法的最后调用了 Looper.loop(),在这个方法中处理主线程的任务调度,一旦执行完这个方法就意味着APP被退出了,如果我们要避免APP被退出,就必须让APP持续执行Looper.loop()。

package android.app;
public final class ActivityThread extends ClientTransactionHandler {
    ...
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        ...
        Looper.loop();
        throw new RuntimeExcep
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值