windowsInTransulcent引发的问题
现象:在从批注选择路径保存时,连续点击选择路径按钮,会出现闪退。
正常现象应未从批注进入文件管理器选择保存路径。
问题分析
1.为什么连续点击时,应用会闪退
查看打印,并未发现明显异常,通过adb shell dumpsys activity 查看任务栈
//异常时 1.进入批注前的activity 2.文件管理器 3.批注 //正常时 1.文件管理器 2.批注 3.进入批注前的activity
分析发现,其实应用并未闪退,而是在点击时,先跳转到目标activity,再进入上一个应用的activity。
再进一步分析生命周期相关打印,发现上一个Activity的OnStop()方法并未执行。最后排查发现时因为批注应用,需要背景透明,设置了windowsInTransulcent属性为true导致出现问题。
<!-- 设置activity完全透明 --> <style name="TranslucentTheme" parent="Theme.AppCompat.Light.Dialog"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> </style>
2.为什么windowsInTransulcent为true是上一个activity不调用onStop()方法?
起初虽然查看了adnroid的生命周期文档,在OnStop中又这么一段话:
如果您的 Activity 不再对用户可见,说明其已进入“已停止”状态。
但是我仍不是十分理解为什么谷歌要这么设计,直到我看到多窗口模式的说明
在android7.0之后,出现了多窗口模式,在多窗口模式下,虽然用户可以看到两个应用,但是与用户交互的应用位于前台且具有焦点。该Activity处于OnPause状态,而另一个窗口位于OnResume状态。
基于多窗口模式的描述,也不难理解为什么在windowsInTransulcent为true时,上一个activity的onStop()方法不执行(Activity既然是可见,应该也可以被用户正常交互才对嘛)。也能更好的回答为什么会出现crash的假象,即在跳转到其他activity过程中,因为上一个activity未执行onStop()方法而导致在连续点击时,响应了点击事件重新回到了栈顶。(猜测在android7.0之前,不存在此问题)
解决方法
将windowsInTransulcent置为false后问题解决。因为并不是一个应用中所有activty都需要背景透明,在不需要透明时,将属性置为false,让上一个activity进入OnStop状态。
最后再贴出android生命周期的部分内容
OnResume()
Activity 会在进入“已恢复”状态时来到前台,然后系统调用
onResume()
回调。这是应用与用户互动的状态。应用会一直保持这种状态,直到某些事件发生,让焦点远离应用。此类事件包括接到来电、用户导航到另一个 Activity,或设备屏幕关闭。当 Activity 进入已恢复状态时,与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_RESUME 事件。这时,生命周期组件可以启用在组件可见且位于前台时需要运行的任何功能,例如启动相机预览。
当发生中断事件时,Activity 进入“已暂停”状态,系统调用
onPause()
回调。如果 Activity 从“已暂停”状态返回“已恢复”状态,系统将再次调用
onResume()
方法。因此,您应实现onResume()
,以初始化在onPause()
期间释放的组件,并执行每次 Activity 进入“已恢复”状态时必须完成的任何其他初始化操作。
OnStop()
如果您的 Activity 不再对用户可见,说明其已进入“已停止”状态,因此系统将调用
onStop()
回调。例如,当新启动的 Activity 覆盖整个屏幕时,可能会发生这种情况。如果 Activity 已结束运行并即将终止,系统还可以调用onStop()
。当 Activity 进入已停止状态时,与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_STOP 事件。这时,生命周期组件可以停止在组件未显示在屏幕上时无需运行的任何功能。
在
onStop()
方法中,应用应释放或调整在应用对用户不可见时的无用资源。例如,应用可以暂停动画效果,或从精确位置更新切换到粗略位置更新。使用onStop()
而非onPause()
可确保与界面相关的工作继续进行,即使用户在多窗口模式下查看您的 Activity 也能如此。您还应使用
onStop()
执行 CPU 相对密集的关闭操作。例如,如果您无法找到更合适的时机来将信息保存到数据库,可以在onStop()
期间执行此操作。以下示例展示了onStop()
的实现,它将草稿笔记内容保存到持久性存储空间中:
协调 Activity
当一个 Activity 启动另一个 Activity 时,它们都会经历生命周期转换。第一个 Activity 停止运行并进入“已暂停”或“已停止”状态,同时创建另一个 Activity。如果这些 Activity 共享保存到磁盘或其他位置的数据,必须要明确第一个 Activity 在创建第二个 Activity 之前并未完全停止。相反,启动第二个 Activity 的过程与停止第一个 Activity 的过程重叠。
生命周期回调的顺序已有明确定义,特别是当两个 Activity 在同一个进程(应用)中,并且其中一个要启动另一个时。以下是 Activity A 启动 Activity B 时的操作发生顺序:
Activity A 的
onPause()
方法执行。Activity B 的
onCreate()
、onStart()
和onResume()
方法依次执行(Activity B 现在具有用户焦点)。然后,如果 Activity A 在屏幕上不再显示,其
onStop()
方法执行。