我知道 Android 会破坏当前的活动并重新创建它,因为设备配置在运行时发生了变化。
但是设计这种行为背后的基本原理是什么?
我的意思是为什么要销毁和重新创建当前活动。如果它没有那样发生,有什么缺点吗?
首先,让我们看看Google 对此有何评论:
重新启动行为旨在通过使用与新设备配置匹配的替代资源自动重新加载您的应用程序来帮助您的应用程序适应新配置。
那是什么意思?Android 设计人员决定(大多数*)设计良好的应用程序应该具有针对不同配置量身定制的资源。例如,大多数应用程序在纵向和横向模式下都有不同的布局。不仅如此,语言变化之类的事情可能需要不同的字符串等。
为了解决这个问题,有(至少)两种方法之一可以做到。重新启动整个事情,或者只是加载新资源。
仅加载新资源会给开发人员(IMO)带来额外的负担,迫使他们更深入地思考究竟需要哪些资源,并以某种onConfigChanged()
方法重新加载它们。如果你错过了会发生什么?如果您不按照以前的顺序加载它们怎么办?这会改变事情吗?
通过重新启动整个过程,它可以确保您从一张白纸开始,并且应用程序的响应方式应该与您从一开始就从该配置开始时的方式完全相同(从技术上讲,您已经这样做了)。
*当然,规则也有例外。例如,任何锁定到一个方向的应用程序都不关心方向变化。一些企业应用程序不需要多种语言等。目标是让 90% 的人更容易,而不是 10% 的人。
但是设计这种行为背后的基本原理是什么?
配置更改通常意味着您需要不同的资源:
Android 没有办法替换你所有的资源使用,除非强制你重新加载它们。
如果它没有那样发生,有什么缺点吗?
缺点是开发人员会把它搞砸。
它们将防止活动因某些配置更改而被销毁和重新创建,而其他配置更改则不会,因此当发生其他配置更改时,它们的应用程序会中断。因此,例如,当用户将设备放入桌面扩展坞时,应用程序可能会中断,因为开发人员添加android:configChanges=screenSize|orientation
到清单中并完全忽略了其他配置更改场景。
他们会错过资源。例如,“只需将 android:configChanges=screenSize|orientation 添加到活动标签中”实际上不会修复 UI 以考虑屏幕方向,因此 UI 可能会在底部被截断。或者,开发人员忘记重新加载每个字符串资源,因此现在通过更改区域设置,UI 有一组混合语言。等等。
生命周期流程背后的原因是 android 提供了基于设备配置使用特定资源的机制。
例如,如果您想在纵向模式下使用一个布局文件,而在横向模式下使用不同的布局文件,则使用纵向模式实例化的 Activity 将无法访问横向文件,除非它通过重新创建过程本身。然后,您设计您的 UI 控制器(无论是活动还是片段)以膨胀正确的视图并根据配置使用某些呈现逻辑。Android 为您提供了挂钩来保存在一个配置中加载的数据或状态,然后在配置更改时重新加载它。
95% 的情况下,大多数应用程序/开发人员不使用这种模式,最终使您的代码变得更加冗长,因为必须在配置更改时保存对象的状态,但 android 也提供了一种机制来处理这种情况为你。
Fragment#setRetainInstance是一种机制,您可以将 UI 的状态或数据存储在 Fragment 中,并且当 Activity 旋转时,它将在旋转时使用相同的 Fragment。图案是这样的
//in onCreate in your activity
Fragment myFrag = getSupportFragmentManager().findFragmentByTag("MY_FRAGMENT_TAG");
if(myFrag == null) {
myFrag = new MyFragment();
myFrag.setRetainInstanceState(true);
getSupportFragmentManager().beginTransaction().
.replace(android.R.id.content, myFrag, "MY_FRAGMENT_TAG");
.commit();
}
当 Activity 再次运行其 onCreate 时,它将调用 findFragmentByTag 并且它不会为 null 并且旧片段仍将附加到 UI
只需将清单 android:configChanges=screenSize|orientation 添加到活动标签中