Android - Запобігання перезавантаженню WebView під час обертання


90

Коли я обертаю екран, WebView перезавантажує всю сторінку. У мене цього не може бути, оскільки частина мого вмісту містить динамічний / випадковий матеріал. В даний час при обертанні екран перезавантажує вихідну URL-адресу з методу loadUrl ().

Будь-яка ідея, що не так з моїм кодом?

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
Спрощене рішення, яке я сам використовував і міг би порекомендувати, знаходиться тут: twigstechtips.blogspot.com/2013/08/…
Андріус Барукіс

Відповіді:


103

Я думаю, що основною проблемою є те, що ви викликаєте web.loadUrl (webURL); також при збереженніInstanceState! = null

РЕДАГУВАТИ

Спробуйте:

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

EDIT2 : Вам також потрібні перевизначення 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);
}

Примітка: Будь ласка, додайте у свій AndroidManifest.xml у своєму Activity android: configChanges = "direction | screenSize" Дякую


1
Так! Це працює для мене (після редагування, Тім помітив!)! Дякую! Не могли б ви пояснити, чому і як це працює, і чому ці методи потребували переваги?
позначка


Останнє, чи справді мені потрібне таке твердження if-if: if (savedInstanceState! = Null) ((WebView) findViewById (R.id.web)). RestoreState (savedInstanceState);
позначка

21
це зберігає ту саму сторінку, але все одно перезавантажує на екрані обертання
Grasper

2
Це працює, якщо я додаю властивість android: configChanges до <activity> в AndroidManifest, тож дві речі з вашої відповіді плюс одна. Ось найкраща відповідь , який включає в себе всі три речі: stackoverflow.com/a/46849736/454780
trusktr

63

Не потрібно кодування 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
про які зміни ви говорите?
Пратік Поддар

після коментаря @Mgamerz .. коли справа обертається .. це найгірша пропозиція, яку ви можете дати
Гілерме Олівейра

54
Ніоооооооооооо. Навіть не думайте робити це. Зміни конфігурації не обмежуються обертанням. Також стан екземпляра можна відновити після повернення з низької пам’яті. Проблема полягає в тому, що конфігурація не буде оновлена ​​належним чином, коли ви це зробите. Будь ласка, ніхто цього не роби.
Ерік Кохран

6
@EricCochran Чи можете ви написати правильну відповідь, якщо ви її знаєте? Прийнята відповідь все одно перезавантажує сторінку для мене, а також втрачає інформацію про сеанс. Що в моєму випадку схоже на вау, ви включаєте телефон - вам доведеться входити знову.
Атомоськ,

Це може бути лише частиною повної відповіді. Дивитися це краще один: stackoverflow.com/a/46849736/454780
trusktr

19

у тезі (маніфест)

android:configChanges="orientation|screenSize"

8
Насправді немає жодної причини замінювати onConfigurationChangedметод, оскільки не додається спеціальна функціональність. Просто внесення змін у файл маніфесту зробило для мене фокус.
i2097i

маніфесту було достатньо, і підтримка лише за додаванняorientation|screenSize
Варун Гарг

14

Додавання 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

8

Я не вірю, що це вже спрацює. У моєму випадку відновлення стану за допомогоюWebView.restore(Bundle savedInstanceState) все одно викликає перезавантаження URL-адреси.

Дивлячись на документи для restoreState()ви побачите , що говорить:

Якщо його викликати після того, як цей WebView мав можливість побудувати стан (завантажити сторінки, створити список зворотного / пересилання тощо), можуть виникнути небажані побічні ефекти.

і

Зверніть увагу, що цей спосіб більше не відновлює відображувані дані для цього WebView.

Реквізит @ e4c5 за те, що він направив мене у правильному напрямку у своєму відповів

І звичайно, крайнім шляхом буде запобігання змінам орієнтації, що спричинять руйнування / створення діяльності. Документація щодо того, як це зробити, знаходиться тут



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");

4

Спробуйте це у своєму файлі маніфесту:

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

4

Помістіть це у файл Manifest.xml:

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

Як цитується тут ,

Увага: Починаючи з Android 3.2 (рівень API 13), "розмір екрану" також змінюється, коли пристрій перемикається між портретною та альбомною орієнтацією. Таким чином, якщо ви хочете запобігти перезапуску середовища виконання через зміну орієнтації під час розробки для API рівня 13 або вище (як заявлено атрибутами minSdkVersion та targetSdkVersion), ви повинні включити значення "screenSize" на додаток до значення "орієнтації". Тобто ви повинні розробити андроїд: configChanges = "direction | screenSize". Однак, якщо ваша програма націлена на рівень API 12 або нижче, ваша діяльність завжди сама обробляє цю зміну конфігурації (ця зміна конфігурації не перезапускає вашу активність, навіть коли вона працює на пристрої Android 3.2 або новішої версії).

налаштування android:configChanges="orientation|screenSize" вашої діяльності вирішить цю проблему.

Також зверніть увагу на наступне

Пам'ятайте: Коли ви заявляєте про свою діяльність, щоб обробити зміну конфігурації, ви несете відповідальність за скидання будь-яких елементів, для яких ви надаєте альтернативи. Якщо ви заявляєте про свою діяльність, щоб обробляти зміну орієнтації, і у вас є зображення, які повинні змінюватися між альбомною та книжковою, ви повинні повторно призначити кожен ресурс кожному елементу під час onConfigurationChanged ().


3

Це рішення добре працює для мене:

(1) У AndroidManifest.xml додайте цей рядок для android: configChanges = "клавіатура | прихована клавіатура | орієнтація | screenLayout | uiMode | screenSize | najmanшийScreenSize"

Отак (і як відповіді вище)

<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 перевірити saveInstanceState

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

0

Додайте це в Androidmanifest.xml:

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

Тепер, коли одна з цих конфігурацій змінюється, MyActivityне перезапускається. Натомість MyActivityотримує дзвінок на onConfigurationChanged().

Додайте це:

@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();
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.