Android - zapobieganie ponownemu ładowaniu WebView podczas obracania

90

Kiedy obracam ekran, WebView ponownie ładuje całą stronę. Nie mogę tego mieć, ponieważ niektóre moje treści zawierają dynamiczne / losowe materiały. Obecnie po obróceniu ekran ładuje ponownie oryginalny adres URL z metody loadUrl ().

Masz jakiś pomysł, co jest nie tak z moim kodem?

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>
znak
źródło
1
Uproszczone rozwiązanie, którego sam użyłem i mógłbym polecić, jest tutaj: twigstechtips.blogspot.com/2013/08/…
Andrius Baruckis

Odpowiedzi:

103

Myślę, że głównym problemem jest wywołanie web.loadUrl (webURL); także, gdy saveInstanceState! = null

EDYTOWAĆ

Próbować:

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

EDIT2 : Potrzebujesz także zastąpienia onSaveInstanceState i 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);
}

Uwaga: proszę również dodać w swoim AndroidManifest.xml w swojej aktywności android: configChanges = "orientacja | screenSize" Dziękujemy

Giuseppe
źródło
1
Tak! U mnie to działa (Tim zauważył po edycji!)! Dziękuję Ci! Czy mógłbyś ewentualnie wyjaśnić, dlaczego i jak to działa i dlaczego te metody wymagały zastąpienia?
znak
I ostatnia rzecz, czy naprawdę potrzebuję następującej instrukcji if: if (saveInstanceState! = Null) ((WebView) findViewById (R.id.web)). RestoreState (saveInstanceState);
znak
21
to zachowuje tę samą stronę, ale nadal
ładuje się
2
Działa to, jeśli dodam właściwość android: configChanges do <activity> w AndroidManifest, więc dwie rzeczy z Twojej odpowiedzi plus ta. Oto lepsza odpowiedź, która obejmuje wszystkie trzy rzeczy: stackoverflow.com/a/46849736/454780
trusktr
63

Nie jest wymagane kodowanie w Javie. użyj tego w swoim pliku manifestu.

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

lubić:

<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>
Vettiyanakan
źródło
2
o jakich zmianach mówisz?
Pratik Poddar
po komentarzu @Mgamerz .. kiedy sprawa się kręci .. to jest najgorsza sugestia, jaką możesz dać
Guilherme Oliveira
54
Noooooooooooo. Nawet nie myśl o tym. Zmiany konfiguracji nie ograniczają się do rotacji. Stan instancji można również przywrócić po powrocie z małej ilości pamięci. Problem polega na tym, że konfiguracja nie zostanie poprawnie zaktualizowana, gdy to zrobisz. Proszę, nikt tego nie robi.
Eric Cochran
6
@EricCochran Czy mógłbyś napisać poprawną odpowiedź, jeśli ją znasz? Zaakceptowana odpowiedź nadal ładuje stronę ponownie, a także traci informacje o sesji. Co w moim przypadku jest jak wow, włączasz telefon - musisz się ponownie zalogować.
Atomosk
Może to być tylko część pełnej odpowiedzi. Zobacz to lepsze: stackoverflow.com/a/46849736/454780
trusktr
19

w tagu (manifest)

android:configChanges="orientation|screenSize"
01wifi01
źródło
8
W rzeczywistości nie ma powodu, aby zastępować tę onConfigurationChangedmetodę, ponieważ nie dodano żadnych niestandardowych funkcji. Samo wprowadzenie zmiany w pliku manifestu załatwiło sprawę.
i2097i
manifest był wystarczający i zagłosuj tylko za dodaniemorientation|screenSize
Varun Garg
14

Dodanie android:configChanges="orientation|screenSize"manifestu działa dla mnie

<activity
            android:name="com.example.HelloWorld.WebActivity"
            android:label="@string/title_activity_web"
            android:configChanges="orientation|screenSize" >
</activity>
Rasel
źródło
Czy możesz opublikować, co robi Twoja MainActivity w odniesieniu do WebView?
trusktr
8

Nie wierzę, że to już zadziała. W moim przypadku przywrócenie stanu za pomocą WebView.restore(Bundle savedInstanceState)nadal wyzwala ponowne załadowanie adresu URL.

Patrząc na docs dla restoreState()zobaczysz mówi:

Jeśli zostanie wywołany po tym, jak ten WebView miał szansę zbudować stan (załadować strony, utworzyć listę wstecz / dalej itp.), Mogą wystąpić niepożądane efekty uboczne.

i

Należy pamiętać, że ta metoda nie przywraca już danych wyświetlania dla tego WebView.

Podziękowania dla @ e4c5 za wskazanie mi właściwego kierunku w swojej odpowiedzi

Oczywiście skrajnym działaniem byłoby zapobieganie powodowaniu przez zmiany orientacji niszczenia / tworzenia aktywności. Dokumentacja, jak to zrobić, znajduje się tutaj

Ranjeev Mahtani
źródło
6

Dodaj ten kod w Manifest

<activity 
     ...
     android:configChanges="orientation|screenSize">
Dezorientować
źródło
4

Zastąp onConfigChangemetodę, aby uniknąć ponownego ładowania danych przy zmianie orientacji

Twojej aktywności w AndroidMainfestpliku.

android:configChanges="orientation|keyboardHidden" 

i miej je również w ustawieniach WebView

webview.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
webview.loadUrl("Your URL To Load");
Sampath Kumar
źródło
4

Spróbuj tego w swoim pliku manifestu:

android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
Ajeet Yadav
źródło
4

Umieść to w działaniu pliku Manifest.xml:

android:configChanges="orientation|screenSize"

Oto przykład:

<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>
Carlos Alberto Gonzalez
źródło
4

Jak tu cytowano ,

Uwaga: począwszy od Androida 3.2 (poziom interfejsu API 13) „rozmiar ekranu” zmienia się również, gdy urządzenie przełącza się między orientacją pionową i poziomą. Dlatego jeśli chcesz zapobiec ponownym uruchomieniom środowiska wykonawczego z powodu zmiany orientacji podczas programowania interfejsu API na poziomie 13 lub wyższym (zgodnie z deklaracjami atrybutów minSdkVersion i targetSdkVersion), oprócz wartości „orientacja” należy dołączyć wartość „screenSize”. Oznacza to, że musisz zdekalować androida: configChanges = "orientacja | rozmiar ekranu". Jeśli jednak Twoja aplikacja jest przeznaczona dla interfejsu API na poziomie 12 lub niższym, aktywność zawsze sama obsługuje tę zmianę konfiguracji (ta zmiana konfiguracji nie powoduje ponownego uruchomienia działania, nawet jeśli jest uruchomiona na urządzeniu z systemem Android 3.2 lub nowszym).

ustawienie android:configChanges="orientation|screenSize"Twojej aktywności rozwiąże ten problem.

Zwróć także uwagę na następujące kwestie

Pamiętaj: kiedy deklarujesz swoją aktywność w celu obsługi zmiany konfiguracji, jesteś odpowiedzialny za zresetowanie wszystkich elementów, dla których podajesz alternatywy. Jeśli zadeklarujesz swoje działanie do obsługi zmiany orientacji i masz obrazy, które powinny zmieniać się między poziomą a pionową, musisz ponownie przypisać każdy zasób do każdego elementu podczas onConfigurationChanged ().

davejoem
źródło
3

U mnie to rozwiązanie działa dobrze:

(1) W AndroidManifest.xml dodaj tę linię android: configChanges = "keyboard | keyboardHidden | Orientacja | screenLayout | uiMode | screenSize | smallestScreenSize"

W ten sposób (i jak powyższe odpowiedzi)

<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) Następnie w MainActivity.java sprawdź plik 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) a następnie:

@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);
}
Adrian S.
źródło
0

Dodaj to w Androidmanifest.xml:

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

Teraz, gdy jedna z tych konfiguracji ulegnie zmianie, MyActivitynie uruchamia się ponownie. Zamiast tego MyActivityodbiera telefon onConfigurationChanged().

Dodaj:

@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();
    }
}
Sunny Singh
źródło