Android 异常重启--踩坑归来--干货篇

如果你未对自己的app进行过处理,那么线上各种偶发莫名其妙的闪退、白屏、数据丢失,请检查一下是否因此而引发的。

起因

异常重建指的是非配置变更情况下导致的 Activity 重新创建。

常见场景大多是因为内存等资源不足,从而导致后台应用被系统回收 ,当我们切换到前台时,从而触发的重建,这个机制在Android中为 Low Memory Killer 机制,简称 LMK

引发问题

  1. 静态变量丢失、全局数据、单例丢失
  2. 第三方静态变量丢失(oss等)
  3. 自己维护的Activity栈丢失
  4. Activity + fragment构造,Fragment恢复异常白屏
  5. fragment构造函数中直接传值会闪退
  6. 表单信息、输入信息、操作信息丢失。
  7. 大数据恢复困难
效果

1.MainActivity.java中声明了一个静态变量

2.在下一个Activity中打印了静态变量的情况

 3.正常情况,public static,正常;myList.size()==2

4.异常重启后,静态变量丢失,myList.size()==0

验证方式

开发者模式 - 开启限制后台进程,将应用切到后台,打开其他应用消耗内存,并切回应用查看情况。

 

生命周期情况

根据App切到后台时间、内存情况、操作系统可能有所不同。
可能1:application重启、当前栈顶activity重启,并触发异常存取数据方法;
可能2:application重启,并重启welcome页,类似于冷启动
可能3:正常热启动

解决

数据存储与恢复,很多依赖onSaveInstanceStateonRestoreInstanceState。这两方法不过多解释。

1.静态变量丢失、全局数据、单例丢失 ★★★★

使用永久化技术存储重要的数据。如sp、mmkv、sqlite等。
写一个公共的读写变量的方法,如果该静态变量=null,则先去SharedPreferences里恢复,然后再读出数据。

2.第三方对象丢失 ★★★

将第三方初始化移动到application中
一些同学因为上架市场隐私问题,将第三方的初始化移出了application。解决:第一次在同意协议的activity中初始化,然后再sp里存下状态值true。在application里判断这个sp中的状态值,若为true则在application里初始化。

3.自己维护的Activity栈丢失(不完美解决)★

解决:在异常重启时,恢复数据的方法onSaveInstanceState里判断是否异常重启。如果异常重启就将当前activity加入栈。
解决了获取栈顶activity空指针的问题,但是整个栈未恢复。 (尝试解决:异常存数据时,将整个栈 存起来,以便恢复)
结果:可以正常获取栈顶activity,不会闪退

4.Activity + fragment(ViewPager)构造,Fragment恢复异常白屏 ★★★★★

分析:异常重启activity时,会走完整的activity生命周期,故会重新创建fragment。
若未处理,则activity会存下原先的AFragment(无信息)并且在异常重启时恢复。而重新走生命周期onCreate又会让我们在逻辑上再次创建出一个AFragment,造成出现2个AFragment对象存在。使用时会造成显示错乱、数据传输错乱等

若使用ViewPager加载fragment,则还会造成白屏的情况。
原因接上面分析,在FragmentPagerAdapterinstantiateItemattach时,会找mFragmentManager里的旧的fragment导致白屏、数据错乱等

解决方案:

  • 1.在activity里new Fragment时,先去FragmentManager里找,有则直接复用(好。但是改动多)

  • 2.在异常存数据时,不存fragments信息(改动少,但是耗资源)

  • 3.在取的时候,不取fragments(同2)

方案2实现方式:

在BaseActivity中:

存储

 恢复

方案2源码依据:
存储

FragmentActivityonSaveInstanceState里,会将fragmentkey :  "android:support:fragments"存到outState

 

FragmentActivity的父类Activity.java中,又以android:fragmentskey,存储fragments

恢复

FragmentActivityonCreate时,取出存储的fragment信息,恢复到mFragmentManager

若使用ViewPager(FragmentPagerAdapter)加载fragment,则还会造成白屏的情况。

FragmentPagerAdapterinstantiateItemattach时,会找mFragmentManager里的旧的fragment导致白屏

5.在fragment构造函数中直接传值会闪退 ★★

若fragment中无,无参构造函数,则在异常重启后会闪退。(反射方式启动无参构造函数)
故不能直接在fragment的构造函数中传值。原因同上4。

例:

6.View:用户操作数据、输入恢复/不恢复 ★★★★

系统View大部分都覆写过View.onSaveInstanceState()View.onRestoreInstanceState(),如EditText会存下输入信息、光标信息等。具体View需要阅读源码 + 测试后才能得到实际结果。

自定义View需要开发者自己覆写View.onSaveInstanceState()、View.onRestoreInstanceState()

但是往往自带的存储恢复不能满足我们的使用。比如:搜索框输入模糊搜索内容,但是异常恢复以后,输入内容是恢复了,但是下发列表数据未请求接口显示正确数据。

解决:
1.setSaveEnabled指定是否恢复异常状态

2.覆写onSaveInstanceState()/onRestoreInstanceState()自行处理

源码解析

保存状态逻辑:
Activity会遍历布局层次结构,对于遇到的每个视图,它会调用View.saveHierarchyState(),而View.dispatchSaveInstanceState()会调用View.onSaveInstanceState()。如果View具有id ,则此方法会调用Parcelable,这会将其状态保存到View.dispatchSaveInstanceState()对象并将其返回。 

Parcelable使用Viewid将其保存到共享的持久数据中。

  恢复状态逻辑:
跟保存一致。由Activity下发到window,然后window遍历视图树,根据mID依次恢复每个view状态。id不能重复,否则会抛异常

存储
  1. Activity的window为PhoneWindow

2.调用View的saveHierarchyState并且存在当前window的View焦点信息

3.View.java

那么mViewFlags & SAVE_DISABLED_MASK这个flag又是什么呢?

那么如果我想EditText不恢复之前数据,就可以

 

恢复

 

7.intent传值与大数据存储/恢复 ★★★★

使用intent传值,异常重启时,intent中的值会自动恢复

 

 但是大数据传值受到Binder限制,无法使用intent传值。而onSaveInstanceState()使用的Bundle存值,也受到binder限制

而大数据传值网上有一种方法利用BigBinder传输。
但是此时存入的大数据在进程A,异常恢复后此App的进程变成了B,直接变跨进程通信。对象难以恢复。

此传值方式会造成闪退,因为异常重启后,bundle?.getBinder(key)的类型变成了BpBinder,不是BigBinder

解决:使用mmkv、sqlite等技术永久化存储,然后再恢复。包括大数据传值

8.坑1:FragmentStatePagerAdapter 与 FragmentPagerAdapter 区别 ★★★

在用ViewPager加载Fragment时,有两种Adapter供选择。而他俩却有区别,有坑。

  • FragmentStatePagerAdapter
    1. 在有大量Fragment时使用,在滑动的时候,会回收不用的fragment,故开销较大
    2. 异常保存状态时,saveState/restoreStateViewPager会调用,并由它自行保存fragments

  • 解决
    1. 恢复并复用其原先的fragments  
    2. 在Adapter中重写saveState,不保存fragments

源码

  • FragmentPagerAdapter
    1. 在少量fragment时使用,不会回收fragment,内存占用多。
    2. 异常保存状态时,不会自己存fragments,会取fragmentManage中的fragments

  • 解决:看问题4

源码

 

9.坑2:异常重启与正常启动,supportFragmentManager绑定FragmentPagerAdapter其中有值的时机不一致。 ★

在异常重启时,如果刚绑定view_pager.adapter = fragmentAdapter就使用自定义的方法fragment.setData()传值,此时fragment并未初始化完成。

解决

作者:铁头娃wawa
链接:https://juejin.cn/post/7195837364681277500
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/457466.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型笔记:吴恩达 ChatGPT Prompt Engineering for Developers(1) prompt的基本原则和策略

1 intro 基础大模型 VS 用指令tune 过的大模型 基础大模型 只会对prompt的文本进行续写 所以当你向模型发问的时候,它往往会像复读机一样续写几个问题这是因为在它见过的语料库文本(通常大多来自互联网)中,通常会连续列举出N个问…

【软考】UML中的图之对象图

目录 1. 说明2. 图示3. 特性 1. 说明 1.对象图即object diagram2.展现了某一时刻一组对象以及它们之间的关系3.描述了在类图中所建立的事物的实例的静态快照4.对象图一般包括对象和链5.对象图展示的是对象之间关系,不存在交互,所以不是交互图 2. 图示 …

【FPGA】DDR3学习笔记(二)丨从SDRAM到DDR3的IP核设计

本篇文章包含的内容 一、DDR SDRAM1.1 基本概述1.2 工作时序(以读取为例) 二、DDR2 SDRAM2.1 基本概述2.2 工作时序 三、DDR3 SDRAM3.1 基本概述3.2 硬件设计3.3 读写时序3.4 MIG IP核设计3.5 读写代码设计 开发板:正点原子的达芬奇开发板&am…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:GridCol)

栅格子组件,必须作为栅格容器组件(GridRow)的子组件使用。 说明: 该组件从API Version 9开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 子组件 可以包含单个子组件。 接口 GridCol(option?:{span?: number | …

#QT(一种朴素的计算器实现方法)

1.IDE:QTCreator 2.实验:这是全靠自己想法写的计算器,没有参考任何教程。 (1)这个计算器只要有运算符敲入就会进行一次运算,所以他没有先后之后,无法满足运算优先级。 (2&#xff…

linux安全--Nginx与Tomcat实现负载均衡

目录 1.实验拓扑原理图,前提实现全网互通 2.找到nginx的conf目录中的nginx.conf文件 3.实验效果 1.实验拓扑原理图,前提实现全网互通 搭建全网互通可以看https://blog.csdn.net/m0_74313947/article/details/136008513?spm1001.2014.3001.5501 搭建N…

JavaEE之多线程(创建线程的五种写法)详解

😽博主CSDN主页: 小源_😽 🖋️个人专栏: JavaEE 😀努力追逐大佬们的步伐~ 目录 1. 前言 2. 操作系统"内核" 3. 创建线程的五种写法 (我们重点要掌握最后一种写法!!) 3.1 继承 Thread, 重写 run 3. 2 实现 Runnabl…

北京保险服务中心携手镜舟科技,助推新能源车险市场规范化

2022 年,一辆新能源汽车在泥泞的小路上不慎拖底,动力电池底壳受损,电池电量低。车主向保险公司报案,希望能够得到赔偿。然而,在定损过程中,保司发现这辆车的电池故障并非由拖底事件引起,而是由于…

电脑坏了去维修,第一家报价800,第三家说报废!

这篇文章主要讲的是修理坏掉的电脑。 第一家报价300,第二家报价800,第三家说要报废! 相信很多朋友对于修电脑坏了要多少钱有很多困惑,修电脑坏了要多少钱,到底去正规售后服务还是去非品牌店维修一台坏掉的电脑。 今天高…

基于单片机的电子琴设计

基于单片机的电子琴设计 摘 要 读书、看电影、听音乐,都是最常见的丰富内心世界的良剂。听音乐,作为陶冶情操、提升境界最便捷的方式,正受到越来越多人们的欢迎。音乐可以很轻松的融入各种场合,给人们带来很轻松的氛围&#xff…

基础---nginx 启动不了,跟 Apache2 服务冲突

文章目录 查看 nginx 服务状态nginx 启动后 访问页面 127.0.0.1停止 nginx 服务,访问不了页面停止/启动 Apache2 服务,启动 Apache2 页面访问显示正确nginx 莫名启动不了卸载 Apache2 服务器 启动 nginx ,但是总是不能实现反向代理&#xff0…

微服务分布式springcloud的体育场地预约系统演kdm1z

体育场馆设施预约系统是在实际应用和软件工程的开发原理之上,运用java语言以及Springcloud框架进行开发。首先要进行需求分析,分析出体育场馆设施预约系统的主要功能,然后设计了系统结构。整体设计包括系统的功能、系统总体结构、系统数据结构…

Annaconda环境下ChromeDriver配置及爬虫编写

Anaconda环境的chromedriver安装配置_anaconda 配置chromedriver-CSDN博客 Chromedriver驱动( 121.0.6167.85 ) - 知乎 下载好的驱动文件解压,将exe程序复制到Annaconda/Scripts目录以及Chrome/Application目录下 注意要提前pip install selenium包才能运行成功&a…

若依Vue3图片预览大图遮罩层和表格的border css层级冲突

样式层级出现问题,表格的层级高于图片的层级 1.解决方式一:设置此文件的该属性(z-index)为继承,则显示正常 .el-table .el-table__cell { z-index: inherit; } 2.解决方式二:将此属性设置为true(本人试了…

【Python】快捷找到最大最小 N 个元素

heapq 简单数据结构取出最大最小N个元素复杂数据结构中取出最大最小N个元素代码解析:lambda Python 中有 heapq 模块可以快捷找到数组中最大最小的 N 个元素; heapq.nlargest(num, arr) # 从arr数组中取出最大num个元素 heapq.nsmallest(num, arr) # …

[论文笔记]LLaMA: Open and Efficient Foundation Language Models

引言 今天带来经典论文 LLaMA: Open and Efficient Foundation Language Models 的笔记,论文标题翻译过来就是 LLaMA:开放和高效的基础语言模型。 LLaMA提供了不可多得的大模型开发思路,为很多国产化大模型打开了一片新的天地,论文和代码值…

npm报错,显示certificate has expired

从报错信息就可以知道是因为之前设置的淘宝镜像已过期,解决方法就是要把之前设置的淘宝镜像改成新的 第一种方法 第一步:清空缓存 npm cache clean --force第二步:重新设置新的镜像源 npm config set registry https://registry.npmmirror…

使用canvas实现图纸标记及回显

图纸 图纸标记后的效果图 最近做的一个qms项目里面,需要前端在图纸上实现标记及标记后的内容还要能够回显,然后后端通过标记的点,去读取标记图纸的内容,如一些公式、数据之类的,目前实现的功能有 在图纸上面进行矩形…

点云配准论文阅读1-Research on Three-Dimensional Point Cloud Registration Algorithm

Research on Three-Dimensional Point Cloud Registration Algorithm三维点云配准算法研究 Publisher: IEEE发行者 : IEEE Cite This引用此内容 PDF Yuqing Zhang; Shilong Sun; Jingjing Shang; Minghan Yang张玉清;孙世龙; 尚晶晶;杨明翰 Abstract: Accordi…

88. 合并两个有序数组 (Swift版本)

题目 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意:最终,合并…