【发布时间】:2015-10-30 23:49:39
【问题描述】:
我的网络应用在 Chrome 中运行良好,它可以出色地处理配置更改(例如屏幕旋转)。一切都保存完好。
在我的 Android 应用程序中将我的网络应用程序加载到 WebView 时,网络应用程序会在屏幕方向更改时失去状态。它确实部分保留了状态,即它保留了 <input> 表单元素的数据,但是所有 JavaScript 变量和 DOM 操作都会丢失。
我希望我的 WebView 以 Chrome 的方式运行,即完全保留包括任何 JavaScript 变量在内的状态。需要注意的是,虽然 Chrome 和 WebView 源自相同的代码库,但 Chrome 内部并不使用 WebView。
屏幕方向更改时会发生 Activity(以及任何最终的 Fragment)被销毁然后重新创建。 WebView 继承自 View 并覆盖方法 onSaveInstanceState 和 onRestoreInstanceState 用于处理配置更改,因此它会自动保存和恢复任何 HTML 表单元素的内容以及后退/前进导航历史状态。但是 JavaScript 变量和 DOM 的状态不会被保存和恢复。
建议的解决方案
已经提出了一些解决方案。所有这些都不起作用,仅保留部分状态或以其他方式次优。
为 WebView 分配一个 id
WebView 继承自 View,它具有 setId 方法,也可以在布局 XML 文件中使用 android:id 属性在 <WebView> 元素的声明中声明。这是保存和恢复状态所必需的,但是状态只是部分恢复。这会恢复表单输入元素,但不会恢复 JavaScript 变量和 DOM 的状态。
onRetainNonConfigurationInstance 和 getLastNonConfigurationInstance
和 onRetainNonConfigurationInstance 自 API 级别 13 起已弃用。getLastNonConfigurationInstance
强制屏幕方向
可以通过在AndroidManifest.xml 文件中为<Activity> 元素设置screenOrientation 属性或通过setRequestedOrientation 方法来强制一个Activity 的屏幕方向。这是不希望的,因为它打破了屏幕旋转的预期。这也只涉及屏幕方向的变化,而不涉及其他配置变化。
保留片段实例
不起作用。在片段上调用方法setRetainInstance 确实保留了片段(它不会被破坏),因此片段的所有实例变量都被保留,但是它确实破坏了片段的视图,因此@987654357 @ 确实被破坏了。
手动处理配置更改
configChanges 属性可以在 AndroidManifest.xml 文件中为 Activity 声明为 android:configChanges="orientation|screenSize",以通过阻止 configuration changes 来处理它们。这有效,它可以防止活动被破坏,因此WebView 及其内容被完全保留。然而,这已被劝阻,据说仅用作最后的解决方案,因为它可能会导致应用程序以微妙的方式中断并出现错误。设置configChanges 属性时调用方法onConfigurationChanged。
MutableContextWrapper
听说MutableContextWrapper可以使用,但我没有评估过这种方法。
saveState() 和 restoreState()
WebView 有方法saveState 和restoreState。请注意,根据文档,saveState 方法不再存储 WebView 的显示数据,无论这意味着什么。无论哪种方式,这些方法似乎都不能完全保留 WebView 的状态。
WebViewFragment
WebViewFragment 只是一个方便的片段,它为您包装了WebView,因此可以使用更少的样板代码轻松上手,就像ListFragment 一样。它不做任何额外的状态保留来完全保留状态。
此类在 API 级别 28 中已弃用。
问题
对于WebView 在配置更改时被销毁并丢失其状态的问题,是否有任何真正的解决方案? (如屏幕旋转)
完全保留所有状态的解决方案,包括 JavaScript 变量和 DOM 操作。一个干净的解决方案,而不是建立在黑客或过时的方法上。
【问题讨论】:
标签: android webview android-webview android-view android-configchanges