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

当我旋转屏幕时,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>
80077 次浏览

I think the main problem is that you call web.loadUrl(webURL); also when savedInstanceState != null

EDIT

Try:

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

EDIT2: You also need the onSaveInstanceState and onRestoreInstanceState override.

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


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

Note: Please also add in your AndroidManifest.xml in your Activity android:configChanges="orientation|screenSize" Thanks

EDIT: Found a more suitable solution.

NEW:

In 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>

In WebViewActivity.java file add this to onCreate() method

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

also update onSaveInstanceState

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

and onRestoreInstanceState

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

OLD:

No java coding needed. use this in your manifest file.

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

like:

<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>

Override the onConfigChange method to avoid reloading data on orientation change

on your activity in AndroidMainfest file.

android:configChanges="orientation|keyboardHidden"

and have these as well in your WebView settings

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

Add this code in Manifest

<activity
...
android:configChanges="orientation|screenSize">

in tag (manifest)

android:configChanges="orientation|screenSize"

Adding android:configChanges="orientation|screenSize" in manifest works for me

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

I don't believe this will work anymore. In my case, restoring state using WebView.restore(Bundle savedInstanceState) still triggers a reload of the url.

Looking at the docs for restoreState() you'll see it says:

If it is called after this WebView has had a chance to build state (load pages, create a back/forward list, etc.) there may be undesirable side-effects.

and

Please note that this method no longer restores the display data for this WebView.

Props to @e4c5 for pointing me in the right direction in his answer

And of course, the extreme course of action would be to prevent orientation changes from triggering activity destruction/creation. Documentation for how to do this is here

Try this in your manifest file:

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

Place this in the Manifest.xml file activity:

android:configChanges="orientation|screenSize"

Here is an example:

<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>

As quoted here,

Caution: Beginning with Android 3.2 (API level 13), the "screen size" also changes when the device switches between portrait and landscape orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing for API level 13 or higher (as declared by the minSdkVersion and targetSdkVersion attributes), you must include the "screenSize" value in addition to the "orientation" value. That is, you must decalare android:configChanges="orientation|screenSize". However, if your application targets API level 12 or lower, then your activity always handles this configuration change itself (this configuration change does not restart your activity, even when running on an Android 3.2 or higher device).

setting android:configChanges="orientation|screenSize" on your activity will resolve this issue.

Also, take note of the following

Remember: When you declare your activity to handle a configuration change, you are responsible for resetting any elements for which you provide alternatives. If you declare your activity to handle the orientation change and have images that should change between landscape and portrait, you must re-assign each resource to each element during onConfigurationChanged().

This solution works well for me:

(1) In AndroidManifest.xml add this line android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"

Like this (and like the answers above)

<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) Then in MainActivity.java verify 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) and then:

@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);
}

Add this in Androidmanifest.xml:

<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">

Now, when one of these configurations change, MyActivity does not restart. Instead, MyActivity receives a call to onConfigurationChanged().

Add this:

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


// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
}
else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}