当将我的 Web 应用加载到我的 Android 应用程序中的
WebView
中时,Web 应用在屏幕方向更改时会丢失状态。它只能部分地保存状态,即它会保留 <input>
表单元素的数据,但是所有 JavaScript 变量和 DOM 操作都会丢失。我希望我的 WebView 能像 Chrome 一样运行,即完全保留状态,包括任何 JavaScript 变量。需要注意的是,虽然 Chrome 和 WebView 派生自相同的代码库,但 Chrome 不会在内部使用 WebView。
当屏幕方向改变时,Activity(以及任何可能的Fragments)会被销毁,然后重新创建。 WebView继承自
View
并覆盖了onSaveInstanceState
和onRestoreInstanceState
方法来处理配置更改,因此它会自动保存和恢复任何HTML表单元素的内容以及后退/前进导航历史状态。但是JavaScript变量和DOM的状态不会被保存和恢复。
提出的解决方案
已经有一些提出的解决方案。所有这些解决方案都无法正常工作,只能部分保留状态或以其他方式不够优化。
为WebView分配一个id
WebView
继承自View
,后者拥有setId
方法,该方法也可以在布局XML文件中使用android:id
属性声明<WebView>
元素。这是必要的,以便保存和恢复状态,但状态仅部分恢复。这会恢复表单输入元素,但不会恢复JavaScript变量和DOM的状态。
onRetainNonConfigurationInstance
getLastNonConfigurationInstance
强制屏幕方向
一个 Activity 可以通过在 AndroidManifest.xml 文件中为
<Activity>
元素设置 screenOrientation
属性或通过 setRequestedOrientation
方法来强制其屏幕方向。这是不希望出现的,因为它破坏了屏幕旋转的预期。这也仅涉及屏幕方向的更改,而不涉及其他配置更改。保留片段实例无效。在片段上调用
setRetainInstance
方法确实会保留该片段(它不会被销毁),因此片段的所有实例变量都得以保存,但是它确实会销毁片段的视图,因此 WebView
也会被销毁。手动处理配置更改。
在AndroidManifest.xml
文件中,可以为Activity
声明configChanges
属性,如android:configChanges="orientation|screenSize"
以处理配置更改并防止它们。这种方法可以避免活动被销毁,因此WebView
及其内容完全保留。但是,这已经不被鼓励使用,并且被认为只是最后的解决方案,因为它可能导致应用程序出现微妙的问题和错误。当设置了configChanges
属性时,会调用onConfigurationChanged
方法。
MutableContextWrapper
我听说可以使用MutableContextWrapper
,但我还没有评估过这种方法。
saveState()和restoreState()
WebView
有saveState
和restoreState
方法。根据文档,saveState
方法不再存储WebView的显示数据,不知道具体含义。无论如何,这些方法似乎不能完全保留WebView的状态。
WebViewFragment
WebViewFragment
只是一个方便的片段,为您包装了WebView
,使您可以轻松地开始使用少量的样板代码,就像ListFragment
一样。它不会进行任何额外的状态保存以完全保留状态。
此类在API级别28中已弃用。
问题
有没有真正的解决方案来解决WebView
在配置更改(如屏幕旋转)时被销毁并且失去其状态的问题?
一种可以完全保留所有状态的解决方案,包括JavaScript变量和DOM操作。一种干净的解决方案,不是基于hack或已弃用的方法构建的。
new WebView(getActivity())
会在配置更改时泄漏 Activity 上下文(因为 WebView 仍然持有对初始 Activity 的引用)。此外,在配置更改后打开某些表单元素(如下拉列表)时,WebView 可能会崩溃。 - Marten