文章目录
- 1 关于ANR
- 1.1 ANR定义
- 1.2 ANR分类
- 1.3 主要原因
- 1.4 ANR如何避免
- 1.5 ANR如何解决
- 1.6 Framework中对于ANR的实现
- 2 Activity和Fragment的生命周期有哪些
- 2.1 Activity的正常的生命周期
- 2.1.1 第一次启动
- 2.1.2 打开一个Dialog
- 2.1.3 打开另一个Activity,本Activity的回调
- 2.1.4 再次回到原Activity
- 2.1.5 按back键回退
- 2.1.6 按Home键切换到桌面后又回到该Activity
- 2.1.7 A Activity启动B Activity,AB两个Activity的生命周期
- 2.2 Fragment的生命周期
- 2.3 Activity和Fragment交叉的生命周期
- 2.4 Activity屏幕旋转的生命周期
- 2.4.1 横竖屏切换时调用的生命周期
- 2.4.2 避免横竖屏切换时,Activity的销毁和重建
- 2.5 Activity启动模式中涉及到的生命周期(onNewIntent())
- 2.6 资源内存不足导致优先级低的Activity被杀死
- 2.6.1 优先级的排序
- 2.6.2 杀死的顺序
- 3 Activity启动模式
- 3.1 总述
- 3.2 在AndroidManifest.xml文件中设置launchMode属性
- 3.2.1 Standard
- 3.2.2 SingleTop
- 3.2.3 SingleTask
- 3.2.4 SingleInstance
- 3.3 设置intent的flag属性
- 3.4 两者的联系与区别
1 关于ANR
1.1 ANR定义
application not responding:即应用无响应
1.2 ANR分类
KeyDispatchTimeout 5S
BroadcastReceiver Timeout 10s
ServiceTimeout 20s
1.3 主要原因
APP自身逻辑缺陷,主线程阻塞,死锁等
由于其他进程的CPU占用高,导致APP进程无法抢占cpu时间片
1.4 ANR如何避免
- 使用异步处理耗时操作(网络请求,Socket通信,查询大量SQL语句,复杂逻辑计算)
- 使用Thread或者是HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序相应.因为默认Thread的优先级和主线程相同
- 使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程
- Activity的onCreate和onResume回调中尽量避免耗时的代码.BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理
1.5 ANR如何解决
主要分析两个log文件:
- 采用adb bugreport命令到处对应的log信息
- 采用adb pull导出/data/anr/bugreport-traces.txt文件
- 根据关键字:ANR in 检索出具体的ANR类型,然后可以定位出在具体的pid,和大概的一个时间点.带着这些信息,用pid对应的值在traces文件里面去进行搜索.就可以检索出具体的哪行代码导致了ANR了
关于ANR分析的参考
- 自己的简单分析的地址:
- ANR问题分析的一般套路:https://www.jianshu.com/p/082045769443
- 记一次线程死锁导致的anr问题分析:https://www.jianshu.com/p/93e03f30fe2a
1.6 Framework中对于ANR的实现
Android在系统层实现了一套精密的机制来发现ANR,核心原理是消息调度和超时处理.
所有与ANR相关的消息,都会经过系统进程(system_server)调度,然后派发到应用进程完成对消息的实际处理,同时,系统进程设计了不同的超时限制来跟踪消息的处理.一旦应用程序处理消息不当,超时限制就起作用了.
2 Activity和Fragment的生命周期有哪些
2.1 Activity的正常的生命周期
2.1.1 第一次启动
onCreate()->onStart()->onResume()
2.1.2 打开一个Dialog
onPause()
2.1.3 打开另一个Activity,本Activity的回调
onPause()->onStop()
2.1.4 再次回到原Activity
onRestart()->onStart()->onResume()
2.1.5 按back键回退
onPause()->onStop()->onDestroy()
2.1.6 按Home键切换到桌面后又回到该Activity
onPause()->onStop()->onRestart()->onStart()->onResume()
2.1.7 A Activity启动B Activity,AB两个Activity的生命周期
A Activity.onPause()->
B Activity.onCreate()->B Activity.onStart()->B Activity.onResume()->
A Activity.onStop()->A Activity.onDestroy()
2.2 Fragment的生命周期
onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()
2.3 Activity和Fragment交叉的生命周期
Fragment.onAttach()->Fragment.onCreate()->Fragment.onCreateView()->Fragment.onViewCreated
->Activity.onCreate()->Fragment.onActivityCreated->Fragment.onStart()->Activity.onStart()
->Activity.onResume()->Fragment.onResume()
->Fragment.onPause()->Activity.onPause()->Fragment.onStop()->Activity.onStop()
->Fragment.onDestroyView()->Fragment.onDestroy()->Fragment.onDetach()->Activity.onDestroy()
原文:
2.4 Activity屏幕旋转的生命周期
2.4.1 横竖屏切换时调用的生命周期
- 横竖屏切换时Activity会被销毁和重建
- 主要涉及到onSaveInstanceState()和onRestoreInstanceState()方法的回调
- 销毁时onSaveInstanceState()会在onStop之前回调,和onPause()没有既定的时序关系
- Activity重建以后,会在onStart()之后调用onRestoreInstanceState(),把销毁时保存的数据恢复进去.其中onCreate()方法的Bundle参数也是销毁时保存的数据
- 具体的生命周期:onPause()->onSaveInstanceState()->onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState()->onResume()
2.4.2 避免横竖屏切换时,Activity的销毁和重建
- 在AndroidManifest文件的Activity中指定如下属性:android:configChanges=“orientation|screenSize”
- 在横竖屏切换时会回调如下方法:onConfigurationChanged(Configuration config)
2.5 Activity启动模式中涉及到的生命周期(onNewIntent())
Activity的singleTop 、SingleTask 、SingleInstance三种启动模式中,重复调用的时候会直接调用onNewIntent()方法
参考地址:
2.6 资源内存不足导致优先级低的Activity被杀死
2.6.1 优先级的排序
- 前台activity-正在和用户交互的activiy,优先级最高
- 可见但非前台activity-比如弹出了一个对话框,导致activity可见但是位于无法与用户交互
- 后台activity-已经被暂停的activity
2.6.2 杀死的顺序
当系统内存不足时,会按照上述优先级从低到高去杀死目标Activity所在的进程.
3 Activity启动模式
3.1 总述
Activity的启动模式有两种设置方式,一种是在AndroidManifest.xml文件中设置launchMode属性.还有一种是设置intent的flag属性来实现.
3.2 在AndroidManifest.xml文件中设置launchMode属性
这种方式一共对应着四个值,分别为:standard(默认值)、singleTop 、SingleTask 、SingleInstance
3.2.1 Standard
- 默认值,每次都会创建一个新的Activity.
- 所属堆栈:与启动它的activity在同一个堆栈.跨进程启动5.0后会在新创建的堆栈中.
3.2.2 SingleTop
- 栈顶复用,需要启动的Activity刚好在栈顶,则复用(会回调onNewIntent()方法),否则重新创建
- 所属堆栈:与启动它的activity在同一个堆栈.跨进程启动5.0后会在新创建的堆栈中.
- 应用场景:Notification对应的Activity
3.2.3 SingleTask
- 栈内复用,需要启动的Activity已经在栈中存在,则复用(会回调onNewIntent()方法,并将此实例之上的Activity出栈),否则重新创建.
- 所属堆栈:可以结合taskAffinity属性来指定堆栈,跨进程启动会在新创建的堆栈中
- 应用场景:App的主页
3.2.4 SingleInstance
- 单例模式.会在一个新的堆栈中来创建该实例,如果存在则复用(会回调onNewIntent()方法)
- 所属堆栈:创建一个新的堆栈来单独存放
- 应用场景:程序之间的数据共享
3.3 设置intent的flag属性
- FLAG_ACTIVITY_NEW_TASK:使用一个新的task来启动Activity。通常使用在service中启动Activity
- FLAG_ACTIVITY_NO_HISTORY:使用此模式启动的Activity,该Activity启动完其他Activity以后,此Activity会从栈中消失
3.4 两者的联系与区别
- 优先级上:设置intent的flag属性的优先级会更高
- 限定范围上:设置launchmode属性,没有FLAG_ACTIVITY_NO_HISTORY的功能
设置intent的Flag属性的方法,无法指定singleInstance方式 - 非特殊情况,尽量使用设置launchmode的方式
参考地址:
参考书籍:Android开发艺术探索
鸡汤文一枚:自己太多的时候都是为现状焦虑,却不想改变自己