Android - 防止 WebView 在旋转时重新加载

107

当我旋转屏幕时,WebView会重新加载整个页面。这对我来说是不可接受的,因为我的某些内容包含动态/随机材料。目前,当旋转屏幕时,它会重新加载从loadUrl()方法中的原始URL。

有任何想法我的代码有什么问题吗?

MainActivity.java

package com.mark.myapp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends Activity {

    WebView web;
    String webURL = "http://www.google.co.uk/";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState != null)
            ((WebView)findViewById(R.id.web)).restoreState(savedInstanceState);

        web = (WebView) findViewById(R.id.web);
        web.getSettings().setJavaScriptEnabled(true);
        web.loadUrl(webURL);
        web.setPadding(0, 0, 0, 0);
        web.getSettings().setLoadWithOverviewMode(true);
        web.getSettings().setUseWideViewPort(true);
        web.getSettings().setSupportZoom(true);
        web.getSettings().setBuiltInZoomControls(true);

        web.setWebViewClient(new HelloWebViewClient());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    private class HelloWebViewClient extends WebViewClient {
        public boolean shouldOverrideUrlLoading(WebView web, String url) {
            web.loadUrl(url);
            return true;
        }
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) {
            web.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mark.myapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"

            android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

1
我个人使用过并且推荐的简化解决方案在这里:http://twigstechtips.blogspot.com/2013/08/android-retain-instance-of-webview.html - Andrius Baruckis
12个回答

120

我认为主要问题是当savedInstanceState != null时你也调用了web.loadUrl(webURL)。

编辑

尝试:

if (savedInstanceState == null)
{
  web.loadUrl(webURL);
}

编辑2:您还需要覆盖 onSaveInstanceState 和 onRestoreInstanceState 方法。

@Override
protected void onSaveInstanceState(Bundle outState )
{
super.onSaveInstanceState(outState);
web.saveState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
web.restoreState(savedInstanceState);
}
注意:请在你的Activity中的AndroidManifest.xml文件中添加 android:configChanges="orientation|screenSize"。
谢谢。

1
是的!这对我有用(在编辑后,Tim发现了!)!谢谢!您能否解释一下为什么以及如何运作,以及为什么需要重写那些方法? - mark
在onRestoreInstanceState()中,super调用不应该是super.onRestoreInstanceState()吗?这样做对我很有效。 - Christian García
24
旋转屏幕时保持在同一页面但仍然重新加载。 - Grasper
2
如果我在AndroidManifest的<activity>中添加android:configChanges属性,这将起作用,因此您答案中的两个事项再加上这个。以下是更好的答案,包括所有三个事项:https://dev59.com/eVoU5IYBdhLWcg3w5pya#46849736 - trusktr
1
对我来说,似乎只需将 android:configChanges 属性添加到 AndroidManifest.xml 中的 <activity> 中即可解决。 - Antônio Medeiros
显示剩余6条评论

71

编辑:找到了更合适的解决方案。

新内容:

AndroidManifest.xml中。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.Example.WebviewSample">
    <application
        <activity android:name=".WebViewActivity"
            <!-- ADD THIS -->
            android:configChanges="orientation|screenSize">
        </activity>
    </application>
</manifest>

WebViewActivity.java 文件中,在 onCreate() 方法中添加以下内容

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    wView = (WebView) findViewById(R.id.webView);
    if (savedInstanceState == null) {
        wView.loadUrl("https://google.com");
    }
}

还需要更新onSaveInstanceState方法。

@Override
protected void onSaveInstanceState(Bundle outState)
{
    super.onSaveInstanceState(outState);
    wView.saveState(outState);
}

并且 onRestoreInstanceState

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
    super.onRestoreInstanceState(savedInstanceState);
    wView.restoreState(savedInstanceState);
}

NEW:

无需 Java 编码。 在清单文件中使用此代码。

 android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
如下所示:
<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.Example.WebviewSample.webviewsample"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>        
</application>

2
你在谈论什么变化? - Pratik Poddar
以下是@Mgamerz的评论...当涉及旋转问题时..这是你可能提出的最糟糕的建议。 - Guilherme Oliveira
58
不要!甚至不要考虑这样做。配置更改不仅限于旋转。此外,实例状态可以在从低内存返回后恢复。问题在于这样做时配置将无法正确更新。请勿这样做。 - Eric Cochran
7
@EricCochran,如果你知道正确答案,请写下来。已经被接受的答案对我来说仍然会重新加载页面,而且还会丢失会话信息。在我的情况下,这就像哇,你翻转手机-你必须再次登录。 - Atomosk
这可能只是完整答案的一部分。请参见更好的答案:https://dev59.com/eVoU5IYBdhLWcg3w5pya#46849736 - trusktr

24

在标签中(清单)

android:configChanges="orientation|screenSize"

9
实际上没有理由覆盖onConfigurationChanged方法,因为没有添加任何自定义功能。只需在清单文件中进行更改就可以达到效果。 - i2097i
清单已足够,点赞仅添加 orientation|screenSize - Varun Garg
奇怪的是,破坏性行为是默认设置。没有人会想到旋转网页视图会重新启动Web应用程序。这只是...奇怪。 - trusktr

15

在清单文件中添加android:configChanges="orientation|screenSize"对我很有用

<activity
            android:name="com.example.HelloWorld.WebActivity"
            android:label="@string/title_activity_web"
            android:configChanges="orientation|screenSize" >
</activity>

你能否发布一下你的MainActivity关于WebView的操作? - trusktr
1
@trusktr 这并不需要做任何事情。android:configChanges="orientation|screenSize" 使得当设备旋转时,活动不会重新启动。如果活动从未重新启动,则无需处理其重新启动。 - Donald Duck

9
我不认为这种方法还能再使用了。在我的情况下,使用WebView.restore(Bundle savedInstanceState)恢复状态仍会触发网址重新加载。
查看restoreState()文档,你会看到它说:

如果在此WebView有机会构建状态(加载页面,创建后退/前进列表等)之后调用它,则可能会产生不良副作用。

请注意,此方法不再恢复此WebView的显示数据。

感谢@e4c5在他的回答中指出正确的方向。
当然,极端行动的做法是防止方向更改触发活动的销毁/创建。如何执行此操作的文档在此处

7
请在 Manifest 中添加以下代码。
<activity 
     ...
     android:configChanges="orientation|screenSize">

5

在您的清单文件中尝试使用以下代码:

android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"

5

将以下内容放置在Manifest.xml文件中的Activity标签内:

android:configChanges="orientation|screenSize"

这里有一个例子:

<activity android:name=".MainActivity"
          android:label="@string/app_name"
          android:theme="@style/AppTheme.NoActionBar"
          android:configChanges="orientation|screenSize">
          <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
          </intent-filter>
</activity>

4
这个解决方案对我很有效:
(1)在AndroidManifest.xml中添加以下行 android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
像这样(与上面的答案一样)
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

(2) 接下来在MainActivity.java中验证savedInstanceState。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mainContext = getApplicationContext();
    ----
    myWebView = (WebView) findViewById(R.id.webView);
    prepareWebView();
    myWebView.addJavascriptInterface(myJavaScriptInterface, "WEB2Android");

    if (savedInstanceState == null) {
        myWebView.post(new Runnable() {
            @Override
            public void run() {
                myWebView.loadUrl("http://www.appbiz.ro/foto_konta");
            }
        });
    }
    ----
}

(3) 然后:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
}

@Override
protected void onSaveInstanceState(Bundle outState )
{
    super.onSaveInstanceState(outState);
    myWebView.saveState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
    super.onRestoreInstanceState(savedInstanceState);
    myWebView.restoreState(savedInstanceState);
}

4

重写onConfigChange方法,以避免屏幕旋转时重新加载数据。

AndroidMainfest文件中的活动中执行此操作。

android:configChanges="orientation|keyboardHidden" 

并且在您的 WebView 设置中也需要这些

webview.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
webview.loadUrl("Your URL To Load");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接