App为什么会crash?一篇文章带你探究根本原因 ,事情没有你想得那么简单

App为什么会crash?一篇文章带你探究根本原因 ,事情没有你想得那么简单public void uncaughtExce Thread t Throwable e if parent null parent uncaughtExce t e else Thread UncaughtExce ueh Thread

大家好,我是讯享网,很高兴认识大家。

public void uncaughtException(Thread t, Throwable e) {

if (parent != null) {

parent.uncaughtException(t, e);

} else {

Thread.UncaughtExceptionHandler ueh =

Thread.getDefaultUncaughtExceptionHandler();

if (ueh != null) {

ueh.uncaughtException(t, e);

} else if (!(e instanceof ThreadDeath)) {

System.err.print("Exception in thread “”

  • t.getName() + “” ");

e.printStackTrace(System.err);

}

}

}

然后调用 Thread.getDefaultUncaughtExceptionHandler() 获取默认的 UncaughtExceptionHandler ,然后调用 uncaughtException 方法,既然名字是默认的 uncaughtExceptionHandler 对象,那么必然有初始化的地方,这就需要从系统初始化开始说起,不过初始化流程特别复杂,也不是本篇重点,所以就直接从 RuntimeInit 的 main 方法开始吧。

public static final void main(String[] argv) {

enableDdms();

if (argv.length == 2 && argv[1].equals(“application”)) {

if (DEBUG) Slog.d(TAG, “RuntimeInit: Starting application”);

redirectLogStreams();

} else {

if (DEBUG) Slog.d(TAG, “RuntimeInit: Starting tool”);

}

commonInit();

/*

  • Now that we’re running in interpreted code, call back into native code
  • to run the system.

*/

nativeFinishInit();

if (DEBUG) Slog.d(TAG, “Leaving RuntimeInit!”);

}

作为 java 类, main 方法一直都是执行的入口。从上述代码可以看出, main 方法中会调用 commonInit 方法:

protected static final void commonInit() {

if (DEBUG) Slog.d(TAG, “Entered RuntimeInit!”);

/*

  • set handlers; these apply to all threads in the VM. Apps can replace
  • the default handler, but not the pre handler.

*/

LoggingHandler loggingHandler = new LoggingHandler();

Thread.setUncaughtExceptionPreHandler(loggingHandler);

Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));

…代码省略…

initialized = true;

}

此处会给 Thread 设置一个 KillApplicationHandler 对象,我们可以看到这个 KillApplicationHandler 是实现了 Thread.UncaughtExceptionHandler 这个接口的,所以自然会重写 uncaughtException 方法。

public void uncaughtException(Thread t, Throwable e) {

try {

ensureLogging(t, e);

// Don’t re-enter – avoid infinite loops if crash-reporting crashes.

if (mCrashing) return;

mCrashing = true;

// Try to end profiling. If a profiler is running at this point, and we kill the

// process (below), the in-memory buffer will be lost. So try to stop, which will

// flush the buffer. (This makes method trace profiling useful to debug crashes.)

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

ActivityThread.currentActivityThread().stopProfiling();

}

// Bring up crash dialog, wait for it to be dismissed

ActivityManager.getService().handleApplicationCrash(

mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));

} catch (Throwable t2) {

if (t2 instanceof DeadObjectException) {

// System process is dead; ignore

} else {

try {

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

} catch (Throwable t3) {

// Even Clog_e() fails! Oh well.

}

}

} finally {

// Try everything to make sure this process goes away.

Process.killProcess(Process.myPid());

System.exit(10);

}

}

在代码的最后执行了 System.exit(10) ;这个方法就会直接干掉当前进程,也就是所谓的 App crash 了。

所以我们一旦抛出异常,并且没有捕捉的话,程序就会被强制干掉。

第二个问题:能否让 App 不要 crash

答案自然是肯定的,我们刚才在看代码的时候也看到下面这段代码:

public UncaughtExceptionHandler getUncaughtExceptionHandler() {

//可以看到当uncaughtExceptionHandler没有赋值的时候,会返回ThreadGroup对象


讯享网

return uncaughtExceptionHandler != null ?

uncaughtExceptionHandler : group;

}

只有在我们没有设置 UncaughtExceptionHandler 的时候,才会调用 defaultUncaughtExceptionHandler 对象,所以自然而然的就想到了实现这个类,然后在这里面做相应的处理。

说干就干试试吧:

我们先试一下主动抛出异常的效果吧,先是在 MainActivity 里面放置一个 Button,让它点击可以主动抛出异常:

package com.netease.demo;

import android.os.Bundle;

import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

public void click(View view) throws Exception{

throw new Exception(“主动抛出异常”);

}

}

来看一下执行效果:

不出意料程序崩溃了。。。

那我们接下来写一个 CrashHandler 的类实现了 Thread.UncaughtExceptionHandler 接口:

package com.netease.demo;

import android.util.Log;

// Created by chendanfeng on 2020-08-19.

public class CrashHandler implements Thread.UncaughtExceptionHandler {

private static final String TAG = “CrashHandler”;

@Override

public void uncaughtException(Thread t, Throwable e) {

Toast.makeText(MyApplication.sApp,"uncaughtException : " + e.getMessage(),Toast.LENGTH_SHORT).show();

}

}

然后在 MyApplication 里面对这个 Handler 进行设置:

package com.netease.demo;

import android.app.Application;

// Created by chendanfeng on 2020-08-19.

public class MyApplication extends Application {

public static MyApplication sApp;

@Override

public void onCreate() {

super.onCreate();

sApp = this;

Thread.currentThread().setUncaughtExceptionHandler(new CrashHandler());

}

}

然后再看下效果:

我们发现确实 App 已经不会 crash 了,但是又出现了另外一个问题,那就是 App 卡死在了这个界面,点击无效了。

那么这到底是怎么一回事呢?其实这也不难理解,我们的页面启动的入口是在 ActivityThread 的 main 方法:

public static void main(String[] args) {

…代码省略…

Looper.prepareMainLooper();

…代码省略…

Looper.loop();

throw new RuntimeException(“Main thread loop unexpectedly exited”);

}

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

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

面试复习笔记:

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
给文章留个小赞,就可以免费领取啦~

戳我领取:GitHub

《960页Android开发笔记》

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

戳我领取:GitHub

《960页Android开发笔记》

[外链图片转存中…(img-xqYhPRKP-55)]

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

[外链图片转存中…(img-kKz2EVEm-56)]

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

小讯
上一篇 2025-01-25 07:31
下一篇 2025-04-10 09:36

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/44611.html