Android 在WebView中处理屏幕旋转
我的web应用程序在Chrome上运行得非常好,它可以处理配置更改(如屏幕旋转)。一切都保存完好 将我的web应用加载到安卓应用中时,web应用将在屏幕方向更改时失去状态。它确实部分保留了状态,即它保留了Android 在WebView中处理屏幕旋转,android,webview,android-webview,android-view,android-configchanges,Android,Webview,Android Webview,Android View,Android Configchanges,我的web应用程序在Chrome上运行得非常好,它可以处理配置更改(如屏幕旋转)。一切都保存完好 将我的web应用加载到安卓应用中时,web应用将在屏幕方向更改时失去状态。它确实部分保留了状态,即它保留了表单元素的数据,但是所有JavaScript变量和DOM操作都丢失了 我希望我的WebView能够像Chrome那样运行,即完全保留状态,包括任何JavaScript变量。需要注意的是,虽然Chrome和WebView源自同一代码库,但Chrome内部并不使用WebView 屏幕方向发生的变化是
表单元素的数据,但是所有JavaScript变量和DOM操作都丢失了
我希望我的WebView能够像Chrome那样运行,即完全保留状态,包括任何JavaScript变量。需要注意的是,虽然Chrome和WebView源自同一代码库,但Chrome内部并不使用WebView
屏幕方向发生的变化是活动(以及任何最终的片段)被破坏,然后重新创建WebView
继承并覆盖这些方法,用于处理配置更改,因此它会自动保存和恢复任何HTML表单元素的内容以及后退/前进导航历史状态。但是,不会保存和恢复JavaScript变量和DOM的状态
提议的解决办法
已经提出了一些解决方案。所有这些都不工作,只保留部分状态或以其他方式次优
为WebView分配一个id
WebView
继承自View
,该视图的方法也可以使用
元素声明中的属性在布局XML文件中声明。这是保存和恢复状态所必需的,但状态仅部分恢复。这将恢复表单输入元素,但不恢复JavaScript变量和DOM状态
onRetainNonConfigurationInstance和getLastNonConfigurationInstance
自API等级13起,已弃用
强制屏幕定向
通过设置方法的属性,活动可以强制其屏幕方向。这是不希望的,因为它打破了屏幕旋转的预期。这也只处理屏幕方向的变化,而不处理其他配置的变化
保留片段实例
不起作用。对片段调用方法会保留片段(它不会被销毁),因此片段的所有实例变量都会被保留,但是它会破坏片段的视图,因此WebView
会被销毁
手动处理配置更改
可以在AndroidManifest.xml
文件中将活动的属性声明为android:configChanges=“orientation | screenSize”
以通过阻止它们来处理。这样做可以防止活动被破坏,因此WebView
及其内容得到完全保留。然而,这一直被劝阻,据说只是作为最后的解决方案使用,因为它可能会导致应用程序以微妙的方式中断并出现bug。当设置configChanges
属性时,将调用该方法
可变上下文包装器
我听说可以使用,但我还没有评估过这种方法
saveState()和restoreState()
WebView
有方法和步骤。注意:根据文档,saveState
方法不再存储WebView的显示数据,无论这意味着什么。无论哪种方式,这些方法似乎都不能完全保留WebView的状态
WebViewFragment
这只是一个方便的片段,为您包装了WebView
,因此可以轻松地使用较少的样板代码,就像ListFragment
。它不做任何额外的状态保存来完全保存状态
该类在API级别28中被弃用
问题:
对于WebView
在配置更改时被破坏并失去其状态的问题,有什么真正的解决方案吗?(如屏幕旋转)
一个完全保留所有状态的解决方案,包括JavaScript变量和DOM操作。一个干净的解决方案,不是建立在黑客或不推荐的方法之上。我建议您重新渲染整个内容。我找了一会儿,找不到一个干净的现成的解决方案。所有的东西都表明你让网页在方向改变时重新呈现
但是,如果确实需要持久化JS变量,可以模仿saveState
和restoreState
所做的操作。理想情况下,这些方法分别使用活动的onSaveInstanceState()
和onRestoreInstanceState()
在WebView
中保存和还原内容。由于潜在的内存泄漏,这些方法无法完成它们所做的工作
因此,您只需创建自己的webview(MyWebView扩展webview
)。在这种情况下,有两种方法:saveVariableState()
和restoreVariableState()
。在您的saveVariableState()
中,只需将所需的每个变量保存在一个包中并返回它(public bundle saveVariableState(){}
)。现在,在活动的onSaveInstanceState()
中,调用MyWebView.saveVariableState
并保存它返回的捆绑包。方向更改后,您可以从onRestoreInstanceState
或onCreate
获取捆绑包,并通过构造函数或restoreVariableState
将其传递给MyWebView
这不是黑客攻击,而是保存其他视图数据的正常方式。在WebView
的情况下,不保存视图的数据,而是保存JS变量。在研究和尝试不同的方法后,我发现我认为是最佳的解决方案
它用于在和方法中保留片段实例,以防止WebView
被破坏
MainActivity.java
public class MainActivity extends Activity {
private static final String TAG_FRAGMENT = "webView";
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebViewFragment fragment = (WebViewFragment) getFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment == null) {
fragment = new WebViewFragment();
}
getFragmentManager().beginTransaction().replace(android.R.id.content, fragment, TAG_FRAGMENT).commit();
}
}
public class WebViewFragment extends Fragment {
private WebView mWebView;
public WebViewFragment() {
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_webview, container, false);
LinearLayout layout = (LinearLayout)v.findViewById(R.id.linearLayout);
if (mWebView == null) {
mWebView = new WebView(getActivity());
setupWebView();
}
layout.removeAllViews();
layout.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return v;
}
@Override
public void onDestroyView() {
if (getRetainInstance() && mWebView.getParent() instanceof ViewGroup) {
((ViewGroup) mWebView.getParent()).removeView(mWebView);
}
super.onDestroyView();
}
private void setupWebView() {
mWebView.loadUrl("https:///www.example.com/");
}
}
<activity android:name=".MyActivity">
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name">
WebView webView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_webview, container, false);
webView = v.findViewById(R.id.webView);
if(savedInstanceState != null){
webView.restoreState(savedInstanceState);
} else {
loadUrl();
}
return v;
}
private void loadUrl(){
webView.loadUrl("someUrlYouWant");
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
webView.saveState(outState);
}