记一次使用android studio分析app闪退原因的过程

article/2025/9/14 14:56:20

闪退演示

首页和问题反馈重复切换两次就闪退

(因为是公司内部app,原有视频不做展示)


app架构

app是原生android studio开发的,部分页面是h5开发的,通过WebView和addJavascriptInterface接口实现js与java的交互


页面修改生效问题

1.由于部分页面是h5开发的,我从代码里直接修改对应的html的代码,比如我在账号的label标签后面加个1,再真机调试,结果发现一点变化都没有,并且从全局搜索里也搜不出登录页面有其他代码,这时候很懵觉得不可能会不生效啊

2.后来同事跟我说修改的html代码要打成zip压缩包放到工程目录里,再打包,app在运行的时候会自动解压,这时候我才知道为什么我无法搜索出登录页面其他相关代码,并且修改了也没生效的原因,于是我照做了,并且成功生效了。有必要记录一下


观察日志

可以看到在进入问题反馈的页面的时候,会每隔一秒钟打印一段日志,说明有每秒秒执行一次的线程在不断运行(里面部分中文输出是我加的,因为是先解决完问题再做的记录)

紧接着当我切换页面到首页的时候,直接就报空指针异常了,当时我猜测跟这个定时线程肯定关系,因为我是秉着先理解问题再解决问题的心态,所以决定一步步搞懂问题是如何发生的。

 


页面切换断点跟踪

因为是在页面切换的时候,发生闪退的,所以要从页面切换的时候寻找问题,首先要搞懂页面是如何切换的

1.点击首页的时候通过调用MrCar_PageJump跳转到并且传参home.htm,如下图:

2.MrCar_PageJump:由于不是web方式所以执行else的_ng_transferAPPMethod,如下图:

 

 3._ng_transferAPPMethod:通过调用window.Android.AndroidTransfer进行页面跳转,这个应该是java注入到js里的一个window对象,供js调用java代码用的,如下图:

4.AndroidTransfer:回到java代码里确实看到有这个方法,并且对应的case调用了PageJump方法如下图:

5.PageJump:打断点跟踪到这里发现这才是真正的跳转地方,先是启动了个新的loginActivity,再把当前的loginActivity结束掉(java层大部分页面代码都是写在loginActivity里的),而具体打开的html页面还要根据参数里的jumpUrl决定(jumpUrl在步骤1就指定了),如下图:

 到此搞懂了页面直接是如何跳转的,只是方便我之后排查问题的时候更好的理解代码


定时线程断点跟踪

在观察日志的时候有说到问题反馈页面有个定时线程,我猜测问题就处在这个定时线程,所以跟踪下这个线程的执行流程,这里踩坑过程就不记录了,直接记录跟踪结果了

1.页面载入的时候执行PageInit初始化

2.PageInit调用GetDataFormAPP方法,回调方法是GetUserInfosCallback

 3.GetUserInfosCallback调用了GetUserLocation方法

 

4.GetUserLocation里由于判断不是web模式,所以执行了MrCar_TransferAPPMethod方法,回调是GetCurrentLocationSucc

 5.GetCurrentLocationSucc中调用了GetStationInfosByPhone

6. GetStationInfosByPhone调用的java层的方法,路由参数是MrCarStartRssi

7.java层的case调用了,dispatcher的startLteInfoWithPermissionCheck

 8.startLteInfoWithPermissionCheck调用了loginactivity重写的startLteInfo

 9.startLteInfo调用了DoubleRSSITest类的exec方法

 10.成功的找到了这个每秒执行一次的定时线程,每秒调用一次handler.sendEmptyMessage方法

 

11.提供了stop方法,以便外界结束这个定时线程

12.分析handler,在DoubleRSSITest的构造器里handler = new MyHandler,是一个继承关系的自定义handler

 

重写了handleMessage方法,当收到消息后处理完消息,通过sendBroadcast方法将消息分发出去

 

loginActivity先是注册了广播关键字my_local_broadcast,所以handler的广播消息会被转发到loginActivity的receiver里

ok,到这里就基本知道了这个定时线程的由来以及工作模式了,并且通过单词和注释知道了这个线程是在每秒刷新手机信号


空指针异常原因分析

其实闪退的时候日志里的保存信息,有指向到这个receiver里

就是因为这个切换页面的时候,phoneManger为null了,导致调用不到方法抛异常

于是我猜测页面切换的时候,有代码把phoneManager置为null了,结果我全局搜索并没有相关代码,所以肯定是别的原因为null了

接着分析,既然phoneManager不是人为的为null,肯定是自然为null,那么只有一种可能phoneManager对象在切换页面的时候被回收了,根据之前的页面跳转断点分析得知,跳转后会启动一个新的activity,然后当前的activity会执行finish方法,这个就会导致当前的activity里面的变量被销毁,从而导致这个定时线程收到消息后分发到revice里,再次访问phoneManager就会访问不到,最终导致报错闪退!binggo!脑子里瞬间就能把报错的过程推算出来了,就像看到了案发现场从而联想到作案手法!

 但是为什么activity都finish了,后台线程怎么会还在执行呢,经过分析,切换页面的时候确实执行了stop方法,线程应该停止,按理来说,不会发生这种情况的

后来经过复盘整个执行过程,页面切换的流程应该是:

 Finish(销毁变量)-> revice(消息回调)-> stop(停止发送)

说白了就是stop完了,在stop之前消息就已经到达了,但是变量又被finish销毁了,所以最终报空指针异常。整个流程一步步跟踪下来直到找到问题很有成就感


解决问题 

既然找到了问题,肯定就要解决问题,试过把stop放在onDestroy的第一句代码调用依然会有几率会报错,因为stop只是改变布尔变量值,并不能立即强制结束线程。所以只能在消息回调里做处理,在recever里加个判空判断,这样子在页面销毁后的最后一次消息回调就不会报错,因为被判空了,从而解决问题

前面分析了这么多代码,最后一个判空判断就搞定了,想想还挺搞笑的,但是没有前面的分析作为基础,我不一定能定位到这个地方,而且我是秉着先理解问题再解决问题的心态完成这件事的,这样才能学到东西


修复后效果演示

(因为是公司内部app,原有视频不做展示)


http://chatgpt.dhexx.cn/article/QycGo9uj.shtml

相关文章

app闪退分析

一、网络异常引起的 1.网络异常引起的,服务端响应不及时,可能导致闪退,检查网络配置情况 二、版本过低 1.应用版本过低,app的sdk和手机的系统不兼容,造成闪退 2.有些api在老版本中有,在新版本中没有&am…

线程池的组成及种类

文章目录 一、 线程池的组成结构二、常见的线程池种类三、线程池的工作流程四、线程池的好处五、小结 我们知道一个进程可以把任务分成多个部分交给线程执行,多线程技术减少了CPU闲置时间,增加了程序并发性。 假设创建线程的时间为t1,执行任务的时间为t2…

Java 中几种常用的线程池

概述: 在java内置API中操作线程所用到的类为Thread。创建线程一般有两种方式, 继承Thread方式实现Runnable方式,并以runnable作为target创建Thread 在Android中的耗时任务一般都需要另开线程来执行,常常需要用线程池来管理这些…

面试官:线程池有哪几种创建方式,能详细的说下么?

根据摩尔定律所说:集成电路上可容纳的晶体管数量每 18 个月翻一番,因此 CPU 上的晶体管数量会越来越多。 但随着时间的推移,集成电路上可容纳的晶体管数量已趋向饱和,摩尔定律也渐渐失效,因此多核 CPU 逐渐变为主流&a…

JAVA常用的几种线程池

1. 为什么使用线程池 诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务。请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP、FTP 或 POP)、通过 …

java线程池详解及五种线程池方法详解

基础知识 Executors创建线程池 Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,比如Executors.newFixedThreadPool(int nThreads),但是便捷不仅隐藏了复杂性,也为我们埋下了潜在的隐患(OOM&#x…

Java常见的线程池有哪些?

1、什么是线程池 java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。 假设一个服务…

线程池的使用(7种创建方法)

目录 1. 固定数量的线程池 a. 线程池返回结果 b. ⾃定义线程池名称或优先级 2. 带缓存的线程池 3. 执⾏定时任务 a. 延迟执⾏(⼀次) b. 固定频率执⾏ c. scheduleAtFixedRate VS scheduleWithFixedDelay 4. 定时任务单线程 5. 单线程线程池 6. 根据当前CPU⽣成线程池 7. Threa…

线程池原理常用四大线程池及七大参数

目录 前言常用的四种线程池newCachedThreadPool——可缓存线程池newFixedThreadPool————指定线程数量newSingleThreadExecutor————单线程的ExecutornewScheduleThreadPool——定时线程池 线程池七大参数corePoolSize——核心线程最大数maximumPoolSize——线程池最大线…

创建线程池的七种方式

在 Java 语言中,并发编程往往都是通过床架线程池来实现的,而线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景。总结来说线程池的创建可以分为两大类: 通过 Executors 创建 通过 ThreadPoolExecutor 创建…

Java中常用的四种线程池

在Java中使用线程池,可以用ThreadPoolExecutor的构造函数直接创建出线程池实例,在Executors类中,为我们提供了常用线程池的创建方法。 ​ 接下来我们就来了解常用的四种: newFixedThreadPool 首先,看一下这种线程池的…

5种常用的线程池

目录 0 概述1 newCachedThreadPool(可缓存的线程池)2 newFixedThreadPool(固定大小的线程池)3 newScheduledThreadPool(可做任务调度的线程池)4 newSingleThreadPool(单个线程的线程池&#xff…

java中的线程池有哪些,分别有什么作用?

阅读完本篇文章会知道如下三点: 1.进程-线程简单介绍 2.java的线程池是什么,有哪些类型,作用分别是什么 3.使用线程池的优点 1.进程-线程的简单介绍 进程 什么是进程呢? 进程是计算机中的程序关于某数据集合的一次运行活动&…

线程池有几种创建方式?

总体来说线程池的创建可以分为以下两类: 通过 ThreadPoolExecutor 手动创建线程池通过 Executors 执行器自动创建线程池。 而以上两类创建线程池的方式,又有 7 种具体实现方法,这 7 种实现方法分别是: Executors.newFixedThre…

创建线程池有哪几种方式

通常开发者都是利用Executors提供的通用线程池创建方法,去创建不同配置的线程池,主要区别在于不同的 Executors目前提供了5种不同的线程池创建配置: 1、newCachedThreadPool(),它是用来处理大量短时间工作…

Java常见的5种线程池

在开发过程中我们常常需要使用到多线程来提高我们代码处理某些任务的效率,最基本的两种创建多线程的方式分别是继承Thread类和实现Runnable接口。但是创建线程和销毁线程的系统开销比较大,而且过多的线程会占用过多的内存等资源。在《阿里巴巴Java开发手…

4种常用线程池介绍

一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执…

面试突击:线程池有几种创建方式?推荐使用哪种?

在 Java 语言中,并发编程都是通过创建线程池来实现的,而线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景,总体来说线程池的创建可以分为以下两类: 通过 ThreadPoolExecutor 手动创建线程池。…

线程池的分类(5种)

Java面试高频提问点 问题一:线程池的创建方式 文章目录 Java面试高频提问点前言一、线程池的分类1.newCachedThreadPool2.newFixedThreadPool3.newSingleThreadExecutor4.newScheduleThreadPool5.newSingleThreadScheduledExecutor 总结 前言 近期因为上海疫情原因…

docker搭建pxc

1、设置阿里云加速器 先搭建一个加速器为后面下载镜像做准备 2、下载pxc镜像 docker pull percona/percona-xtradb-cluster:5.7.21 #下载镜像 docker tag percona/percona-xtradb-cluster:5.7.21 pxc #改镜像名 docker rmi percona/percona…