private static class LoggingHandler implements Thread.UncaughtExceptionHandler {

public volatile boolean mTriggered = false;

@Override

public void uncaughtException(Thread t, Throwable e) {

mTriggered = true;

if (mCrashing) return;

//打印异常日志

if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid())) {

Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);

} else {

StringBuilder message = new StringBuilder();

message.append(“FATAL EXCEPTION: “).append(t.getName()).append(”\n”);

final String processName = ActivityThread.currentProcessName();

if (processName != null) {

message.append("Process: “).append(processName).append(”, ");

}

message.append("PID: ").append(Process.myPid());

Clog_e(TAG, message.toString(), e);

}

}

}

private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {

private final LoggingHandler mLoggingHandler;

public KillApplicationHandler(LoggingHandler loggingHandler) {

this.mLoggingHandler = Objects.requireNonNull(loggingHandler);

}

@Override

public void uncaughtException(Thread t, Throwable e) {

try {

ensureLogging(t, e);

if (mCrashing) return;

mCrashing = true;

if (ActivityThread.currentActivityThread() != null) {

ActivityThread.currentActivityThread().stopProfiling();

}

ActivityManager.getService().handleApplicationCrash(

mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));

} catch (Throwable t2) {

if (t2 instanceof DeadObjectException) {

} else {

try {

Clog_e(TAG, “Error reporting crash”, t2);

} catch (Throwable t3) {

}

}

} finally {

//杀死进程

Process.killProcess(Process.myPid());

System.exit(10);

}

}

private void ensureLogging(Thread t, Throwable e) {

if (!mLoggingHandler.mTriggered) {

try {

mLoggingHandler.uncaughtException(t, e);

} catch (Throwable loggingThrowable) {

}

}

}

}

protected static final void commonInit() {

//设置异常处理回调

LoggingHandler loggingHandler = new LoggingHandler();

Thread.setUncaughtExceptionPreHandler(loggingHandler);

Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));

}

RuntimeInit有两个的内部类,LoggingHandler和KillApplicationHandler。

很显然,LoggingHandler的作用是打印异常日志,而KillApplicationHandler就是App发生Crash的真正原因,其内部调用了Process.killProcess(Process.myPid())来杀死发生Uncaught异常的进程。

我们还发现,这两个内部类都实现了Thread.UncaughtExceptionHandler接口。

分别通过Thread.setUncaughtExceptionPreHandler和Thread.setDefaultUncaughtExceptionHandler方法进行注册。

  • Thread.setUncaughtExceptionPreHandler,覆盖所有线程,会在回调DefaultUncaughtExceptionHandler之前调用,只能在Android Framework内部调用该方法

  • Thread.setDefaultUncaughtExceptionHandler,如果在任意线程中调用即可覆盖所有线程的异常,可以在应用层调用,每次调用传入的Thread.UncaughtExceptionHandler都会覆盖上一次的,即我们可以手动覆盖系统实现的KillApplicationHandler

  • new Thread().setUncaughtExceptionHandler(),只可以覆盖当前线程的异常,如果某个Thread有定义UncaughtExceptionHandler,则忽略全局DefaultUncaughtExceptionHandler

小结:Uncaught异常发生时会终止线程,此时,系统便会通知UncaughtExceptionHandler,告诉它被终止的线程以及对应的异常, 然后便会调用uncaughtException函数。

如果该handler没有被显式设置,则会调用对应线程组的默认handler。如果我们要捕获该异常,必须实现我们自己的handler。

3我们能让应用不发生Crash吗?


上面说到了我们可以在应用层调用Thread.setDefaultUncaughtExceptionHandler来实现所有线程的Uncaught异常的监听,并且会覆盖系统的默认实现的KillApplicationHandler,这样我们就可以做到让线程发生Uncaught异常的时候只是当前杀死线程,而不会杀死整个进程。

这适用于我们的子线程发生Uncaught异常,如果我们的主线程发生Uncaught异常呢?

主线程都被销毁了,这和Crash似乎就没什么区别的。

那么我们有办法让主线程发生Uncaught异常也不会发生Crash吗?

答案是有的,但在讲如何实现之前我们先来介绍一些知识点。

我们知道Java程序开始于一个Main函数,如果只是顺序执行有限任务很快这个Main函数所在的线程就结束了。

如何来保持Main函数一直存活并不断的处理已知或未知的任务呢?

  • 采用死循环。但是死循环的一次循环需要处理什么任务。如果任务暂时没有,也要程序保持活跃的等待状态怎么办?

  • 如果有两个线程或者多个线程如何来协作以完成一个微型系统任务?

如果熟悉Android Handler机制的话,我们会了解到整个Android系统其实是消息驱动的。

Looper内部是一个死循环,不断地MessageQueue内部取出消息,由消息来通知做什么任务。

比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终会通过反射机制,创建Activity实例,然后再执行Activity.onCreate()等方法;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

作为一名从事Android的开发者,很多人最近都在和我吐槽Android是不是快要凉了?而在我看来这正是市场成熟的表现,所有的市场都是温水煮青蛙,永远会淘汰掉不愿意学习改变,安于现状的那批人,希望所有的人能在大浪淘沙中留下来,因为对于市场的逐渐成熟,平凡并不是我们唯一的答案!

资料.png
资料图.jpg

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!**](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐