Android WebView: gestione dei cambiamenti di orientamento


147

Il problema è rappresentato dalle prestazioni successive alla rotazione. WebView deve ricaricare la pagina, che può essere un po 'noiosa.

Qual è il modo migliore di gestire un cambio di orientamento senza ricaricare la pagina dalla fonte ogni volta?


3
"Ricaricando dalla fonte" vuoi dire che sta scaricando di nuovo la pagina, o semplicemente la ridigita?
Jeremy Logan,

La soluzione a cui fa riferimento Blackhex ha risolto il mio problema.
Italo Borssatto,

6
Mi chiedo che diavolo sia così speciale nella mia app che nessuna di queste risposte funziona ...
RobinJ,

Risposte:


91

Se non si desidera che WebView si ricarichi sulle modifiche all'orientamento, è sufficiente sostituire onConfigurationChanged nella classe Activity:

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

E imposta l'attributo android: configChanges nel manifest:

<activity android:name="..."
          android:label="@string/appName"
          android:configChanges="orientation|screenSize"

per maggiori informazioni consultare:
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

https://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges


4
Ho provato ma ho scoperto che non funziona, impostare l'attributo configChanges come di seguito funzionerà. android: configChanges = "keyboardHidden | orientamento"
venerdì

18
farlo è in realtà scoraggiato, come è stato menzionato molte volte prima
Matthias il

3
Matthias: Questo non è proprio vero - vedi Javadoc per WebView.
Krtek,

Due cose da notare su questa soluzione: 1) Se hai un'attività astratta con un WebView, l' configChangesattributo viene aggiunto alla sottoclasse Attività 2) Se l'app dipende da più progetti, l' configChangesattributo viene aggiunto al manifest di quello nella parte superiore dell'albero delle dipendenze (che potrebbe non essere il progetto contenente la classe Activity).
Amanda S

4
Tale onConfigurationChangedsostituzione del metodo è inutile.
Miha_x64,

69

Modifica: questo metodo non funziona più come indicato nei documenti


Risposta originale:

Questo può essere gestito sovrascrivendo la onSaveInstanceState(Bundle outState)tua attività e chiamando saveStatedalla webview:

   protected void onSaveInstanceState(Bundle outState) {
      webView.saveState(outState);
   }

Quindi ripristinalo nel tuo onCreate dopo che la visualizzazione web è stata gonfiata, ovviamente:

public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.blah);
   if (savedInstanceState != null)
      ((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}

26
Questo non funziona con il cambio di orientamento - viene visualizzata una schermata vuota. I metodi saveState \ restoreState vengono chiamati ma non aiutano.
Oleksii Malovanyi,

1
Ecco lo snippet di codice onCreate: setContentView (R.layout.webview); mWebView = (WebView) findViewById (R.id.webview); if (savedInstanceState == null) {mWebView.getSettings (). setJavaScriptEnabled (true); mWebView.setWebViewClient (nuovo SimpleWebViewClient ()); mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } else {mWebView.restoreState (savedInstanceState); }
Oleksii Malovanyi,

12
Dalla documentazione di saveState: si noti che questo metodo non memorizza più i dati di visualizzazione per questo WebView. Il comportamento precedente potrebbe potenzialmente far trapelare file ...
brillenheini,

5
"Si noti che questo metodo non memorizza più i dati di visualizzazione per questo WebView" - developer.android.com/reference/android/webkit/WebView.html
Steven Mark Ford

Qualcuno ha qualche suggerimento su cosa fare ora che "questo metodo non memorizza più i dati di visualizzazione per questo WebView" al fine di impedire il ricaricamento di un modulo WebView?
Lucas P.

24

La migliore risposta a questo sta seguendo Android documentazione trovata qui Fondamentalmente questo impedirà Webview da ricaricare:

<activity android:name=".MyActivity"
      android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection|uiMode"
      android:label="@string/app_name">

facoltativamente , è possibile correggere eventuali anomalie sostituendo onConfigurationChangedl'attività:

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

6
Non ho bisogno del metodo onConfigurationChanged (), ne sono abbastanza sicuro, ma solo l'attributo aggiuntivo nel Manifest. La mia ipotesi è che il supporto nativo per questo sia stato fornito da WebView, e questo è il motivo per cui questa risposta è ora la migliore (perché non ha funzionato quando è stata posta la domanda iniziale)
Booger,

1
Approvo @Booger che non è necessario ignorare il metodo onConfigurationChanged (). Tutto ciò di cui hai bisogno è aggiungere android: configChanges = "orientamento | screenSize" nel file manifest.xml.
Ozanurkan,

5

Ho provato a utilizzare onRetainNonConfigurationInstance (restituendo WebView ), quindi a recuperarlo con getLastNonConfigurationInstance durante onCreate e a riassegnarlo.

Non sembra funzionare ancora. Non posso fare a meno di pensare che sono davvero vicino però! Finora ho solo uno sfondo bianco / bianco WebView . Pubblicare qui nella speranza che qualcuno possa aiutare a spingere questo oltre il traguardo.

Forse non dovrei passare WebView . Forse un oggetto dall'interno WebView ?

L'altro metodo che ho provato, non il mio preferito, è quello di impostare questo nell'attività:

 android:configChanges="keyboardHidden|orientation"

... e quindi non fare praticamente nulla qui:

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  // We do nothing here. We're only handling this to keep orientation
  // or keyboard hiding from causing the WebView activity to restart.
}

Funziona, ma potrebbe non essere considerato una buona pratica .

Nel frattempo, ho anche un unico ImageView che voglio aggiornare automagicamente a seconda della rotazione. Questo risulta essere molto semplice. Sotto la mia rescartella, ho drawable-lande drawable-portper contenere le variazioni orizzontale / verticale, quindi uso R.drawable.myimagenameper l'origine di ImageView e Android "fa la cosa giusta" - yay!

... tranne quando osservi le modifiche alla configurazione, quindi non è così. :(

Quindi sono in contrasto. Usa onRetainNonConfigurationInstance e la rotazione di ImageView funziona, ma la persistenza di WebView non ... o usa onConfigurationChanged e WebView rimane stabile, ma il ImageView non si aggiorna. Cosa fare?

Un'ultima nota: nel mio caso, forzare l'orientamento non è un compromesso accettabile. Vogliamo davvero supportare con garbo la rotazione. Piace molto come fa l'app Browser Android! ;)


7
Non si dovrebbe restituire alcuna vista da onRetainNonConfigurationInstance. Le viste sono associate al contesto attività, quindi se si salva la vista si trasporta tutto quel bagaglio ogni volta che si verifica un cambio di orientamento. La vista è "trapelata". (Vedi l'ultimo paragrafo qui: developer.android.com/resources/articles/… ) La best practice per onRetainNonConfigurationInstance è quella di salvare i dati necessari alla vista, non la vista stessa.
Declan Shanaghy,

3

Un compromesso è quello di evitare la rotazione. Aggiungi questo per correggere l'attività solo per l'orientamento verticale.

android:screenOrientation="portrait"

Questo in realtà funziona in molti casi ed è la soluzione che ho deciso di implementare :-)
Abdo,

1
hehe, questo è un cambiamento di requisito
Max Ch

3

Il modo migliore per gestire i cambiamenti di orientamento e impedire il ricaricamento di WebView su Ruota.

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

Con questo in mente, per evitare che onCreate () venga chiamato ogni volta che cambi orientamento, dovresti aggiungere android:configChanges="orientation|screenSize" to the AndroidManifest.

o solo ..

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

3

Basta scrivere le seguenti righe di codice nel file manifest - nient'altro. Funziona veramente:

<activity android:name=".YourActivity"
  android:configChanges="orientation|screenSize"
  android:label="@string/application_name">

3

Apprezzo che sia un po 'tardi, tuttavia questa è la risposta che ho usato durante lo sviluppo della mia soluzione:

AndroidManifest.xml

    <activity
        android:name=".WebClient"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize" <--- "screenSize" important
        android:label="@string/title_activity_web_client" >
    </activity>

WebClient.java

public class WebClient extends Activity {

    protected FrameLayout webViewPlaceholder;
    protected WebView webView;

    private String WEBCLIENT_URL;
    private String WEBCLIENT_TITLE;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_client);
        initUI();
    }

    @SuppressLint("SetJavaScriptEnabled")
    protected void initUI(){
        // Retrieve UI elements
        webViewPlaceholder = ((FrameLayout)findViewById(R.id.webViewPlaceholder));

        // Initialize the WebView if necessary
        if (webView == null)
        {
            // Create the webview
            webView = new WebView(this);
            webView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
            webView.getSettings().setSupportZoom(true);
            webView.getSettings().setBuiltInZoomControls(true);
            webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
            webView.setScrollbarFadingEnabled(true);
            webView.getSettings().setJavaScriptEnabled(true);
            webView.getSettings().setPluginState(android.webkit.WebSettings.PluginState.ON);
            webView.getSettings().setLoadsImagesAutomatically(true);

            // Load the URLs inside the WebView, not in the external web browser
            webView.setWebViewClient(new SetWebClient());
            webView.setWebChromeClient(new WebChromeClient());

            // Load a page
            webView.loadUrl(WEBCLIENT_URL);
        }

        // Attach the WebView to its placeholder
        webViewPlaceholder.addView(webView);
    }

    private class SetWebClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.web_client, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }else if(id == android.R.id.home){
            finish();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        if (webView.canGoBack()) {
            webView.goBack();
            return;
        }

        // Otherwise defer to system default behavior.
        super.onBackPressed();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig){
        if (webView != null){
            // Remove the WebView from the old placeholder
            webViewPlaceholder.removeView(webView);
        }

        super.onConfigurationChanged(newConfig);

        // Load the layout resource for the new configuration
        setContentView(R.layout.activity_web_client);

        // Reinitialize the UI
        initUI();
    }

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

        // Save the state of the WebView
        webView.saveState(outState);
    }

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

        // Restore the state of the WebView
        webView.restoreState(savedInstanceState);
    }

}

2

Puoi provare a utilizzare onSaveInstanceState()e onRestoreInstanceState()sulla tua attività per chiamare saveState(...)e restoreState(...)sulla tua istanza WebView.


2

È il 2015 e molte persone sono alla ricerca di una soluzione che funzioni ancora su telefoni Jellybean, KK e Lollipop. Dopo molte lotte ho trovato un modo per preservare intatta la visualizzazione web dopo aver cambiato orientamento. La mia strategia è fondamentalmente di memorizzare la visualizzazione Web in una variabile statica separata in un'altra classe. Quindi, se si verifica la rotazione, ricollego la visualizzazione Web dall'attività, attendo il completamento dell'orientamento e ricollego la visualizzazione Web all'attività. Ad esempio ... prima metti questo sul tuo MANIFEST (tastiera nascosta e tastiera sono opzionali):

<application
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name="com.myapp.abc.app">

    <activity
            android:name=".myRotatingActivity"
            android:configChanges="keyboard|keyboardHidden|orientation">
    </activity>

In una CLASSE DI APPLICAZIONE SEPARATA, inserisci:

     public class app extends Application {
            public static WebView webview;
            public static FrameLayout webviewPlaceholder;//will hold the webview

         @Override
               public void onCreate() {
                   super.onCreate();
    //dont forget to put this on the manifest in order for this onCreate method to fire when the app starts: android:name="com.myapp.abc.app"
                   setFirstLaunch("true");
           }

       public static String isFirstLaunch(Context appContext, String s) {
           try {
          SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
          return prefs.getString("booting", "false");
          }catch (Exception e) {
             return "false";
          }
        }

    public static void setFirstLaunch(Context aContext,String s) {
       SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(aContext);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString("booting", s);
            editor.commit();
           }
        }

Nell'ATTIVITÀ inserire:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(app.isFirstLaunch.equals("true"))) {
            app.setFirstLaunch("false");
            app.webview = new WebView(thisActivity);
            initWebUI("www.mypage.url");
        }
}
@Override
    public  void onRestoreInstanceState(Bundle savedInstanceState) {
        restoreWebview();
    }

public void restoreWebview(){
        app.webviewPlaceholder = (FrameLayout)thisActivity.findViewById(R.id.webviewplaceholder);
        if(app.webviewPlaceholder.getParent()!=null&&((ViewGroup)app.webview.getParent())!=null) {
            ((ViewGroup) app.webview.getParent()).removeView(app.webview);
        }
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
        app.webview.setLayoutParams(params);
        app.webviewPlaceholder.addView(app.webview);
        app.needToRestoreWebview=false;
    }

protected static void initWebUI(String url){
        if(app.webviewPlaceholder==null);
          app.webviewPlaceholder = (FrameLayout)thisActivity.findViewById(R.id.webviewplaceholder);
        app.webview.getSettings().setJavaScriptEnabled(true);       app.webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        app.webview.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
        app.webview.getSettings().setSupportZoom(false);
        app.webview.getSettings().setBuiltInZoomControls(true);
        app.webview.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
        app.webview.setScrollbarFadingEnabled(true);
        app.webview.getSettings().setLoadsImagesAutomatically(true);
        app.webview.loadUrl(url);
        app.webview.setWebViewClient(new WebViewClient());
        if((app.webview.getParent()!=null)){//&&(app.getBooting(thisActivity).equals("true"))) {
            ((ViewGroup) app.webview.getParent()).removeView(app.webview);
        }
        app.webviewPlaceholder.addView(app.webview);
    }

Infine, il semplice XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".myRotatingActivity">
    <FrameLayout
        android:id="@+id/webviewplaceholder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</RelativeLayout>

Esistono diverse cose che potrebbero essere migliorate nella mia soluzione, ma ho già speso molto tempo, ad esempio: un modo più breve per convalidare se l'attività è stata avviata per la prima volta invece di utilizzare l'archiviazione SharedPreferences. Questo approccio mantiene intatta la tua visualizzazione web (afaik), le sue caselle di testo, le etichette, l'interfaccia utente, le variabili javascript e gli stati di navigazione che non sono riflessi dall'URL.


1
Perché nemmeno preoccuparsi di staccare e ricollegare WebView quando non viene mai distrutto in primo luogo poiché si gestiscono manualmente le modifiche alla configurazione?
Fred,

@Fred Perché voglio mantenere intatto lo stato della Webview e il suo contenuto, compresi i cookie, e lo stato dei pulsanti e delle caselle di controllo implementati con HTML5 o JS all'interno della pagina Web caricata dalla webview. L'unica regolazione che faccio è il ridimensionamento.
Josh,

Fred significa che non è necessario scollegare / riattaccare la visualizzazione Web tramite una classe statica mentre si dichiarano configChanges nel manifest. In questo modo, le visualizzazioni e l'attività non vengono distrutte durante la rotazione in ogni caso.
Eugene Kartoyev,

2

L'unica cosa che dovresti fare è aggiungere questo codice al tuo file manifest:

<activity android:name=".YourActivity"
      android:configChanges="orientation|screenSize"
      android:label="@string/application_name">

2

Aggiornamento: la strategia attuale è quella di spostare l'istanza di WebView nella classe Applicazione invece del frammento mantenuto quando viene staccato e ricollegarsi al riavvio come fa Josh. Per impedire la chiusura dell'applicazione, è necessario utilizzare il servizio di primo piano, se si desidera mantenere lo stato quando l'utente passa da un'applicazione all'altra.

Se si utilizzano frammenti, è possibile utilizzare l'istanza di conservazione di WebView. La vista Web verrà mantenuta come membro di istanza della classe. Tuttavia, è necessario collegare la vista Web in OnCreateView e scollegarla prima di OnDestroyView per impedirne la distruzione con il contenitore padre.

class MyFragment extends Fragment{  

    public MyFragment(){  setRetainInstance(true); }

    private WebView webView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       View v = ....
       LinearLayout ll = (LinearLayout)v.findViewById(...);
       if (webView == null) {
            webView = new WebView(getActivity().getApplicationContext()); 
       }
       ll.removeAllViews();
       ll.addView(webView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

       return v;
    }

    @Override
    public void onDestroyView() {
        if (getRetainInstance() && webView.getParent() instanceof ViewGroup) {
           ((ViewGroup) webView.getParent()).removeView(webView);
        }
        super.onDestroyView();
    } 
}

I crediti PS vanno alla risposta di kcoppock

Per quanto riguarda 'SaveState ()' non funziona più secondo la documentazione ufficiale :

Si noti che questo metodo non memorizza più i dati di visualizzazione per questo WebView. Il comportamento precedente potrebbe potenzialmente perdere file se restoreState (Bundle) non è mai stato chiamato.


Si noti che mentre setRetainInstanceconserva il frammento la vista (e quindi il WebView) viene comunque distrutta.
Fred,

1
@Fred Puoi fornire una fonte per quella dichiarazione? Ho provato questo in una piccola app che ha un frammento con setRetainInstance (true) che visualizza una pagina di YouTube e se cambio l'orientamento, la vista sembra essere mantenuta poiché il video non viene interrotto. Non sembra che la webview venga distrutta.
Pinkerton,

@Rai È stata solo una lettura errata, ho modificato un po 'la risposta da allora (ha ancora bisogno di alcune correzioni di testo). Se sei interessato allo stato attuale delle cose, questo metodo funziona. Tuttavia, il problema è che Android uccide l'applicazione quando ha poca memoria. Ho un modulo di input importante in cui l'utente deve leggere un messaggio in un'altra applicazione, quindi ho dovuto usare il servizio di primo piano con notifica per evitare che il processo venisse ucciso. Eppure Android continua a distruggere l'attività e quindi il frame mantenuto. Ma l'istanza della classe Application viene preservata, quindi ora sposto WebView in Applicazione.
Boris Treukhov,

1
Uso anche MutableContextWrapper come base di WebView, cambio contesti in attività su collegamento e scollegamento. Un altro grosso problema che Chromium incorpora nei controlli di zoom salva il riferimento alla vecchia attività, quindi nessuna soluzione di zoom con WebView collegata all'applicazione anziché all'attività. TL; DR; se il tuo modulo non è così importante e potresti vivere con il fatto che dopo il cambio di app il tuo processo può essere interrotto e la visualizzazione web non ripristinata vai con la soluzione frame conservata. PS penso anche che i dipendenti di Google siano lontani, lontani dai problemi della vita reale con tutti i loro widget-gadget ..
Boris Treukhov,

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

@Override
protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);    
}

Questi metodi possono essere sovrascritti su qualsiasi attività, in pratica ti permettono semplicemente di salvare e ripristinare i valori ogni volta che un'attività viene creata / distrutta, quando l'orientamento dello schermo cambia l'attività viene distrutta e ricreata in background, quindi puoi usare questi metodi per memorizzare temporaneamente / ripristinare gli stati durante la modifica.

Dovresti dare uno sguardo più approfondito ai due seguenti metodi e vedere se si adatta alla tua soluzione.

http://developer.android.com/reference/android/app/Activity.html



1

Questa è l'unica cosa che ha funzionato per me (ho anche usato lo stato dell'istanza di salvataggio onCreateViewma non era così affidabile).

public class WebViewFragment extends Fragment
{
    private enum WebViewStateHolder
    {
        INSTANCE;

        private Bundle bundle;

        public void saveWebViewState(WebView webView)
        {
            bundle = new Bundle();
            webView.saveState(bundle);
        }

        public Bundle getBundle()
        {
            return bundle;
        }
    }

    @Override
    public void onPause()
    {
        WebViewStateHolder.INSTANCE.saveWebViewState(myWebView);
        super.onPause();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false); 
        ButterKnife.inject(this, rootView);
        if(WebViewStateHolder.INSTANCE.getBundle() == null)
        {
            StringBuilder stringBuilder = new StringBuilder();
            BufferedReader br = null;
            try
            {
                br = new BufferedReader(new InputStreamReader(getActivity().getAssets().open("start.html")));

                String line = null;
                while((line = br.readLine()) != null)
                {
                    stringBuilder.append(line);
                }
            }
            catch(IOException e)
            {
                Log.d(getClass().getName(), "Failed reading HTML.", e);
            }
            finally
            {
                if(br != null)
                {
                    try
                    {
                        br.close();
                    }
                    catch(IOException e)
                    {
                        Log.d(getClass().getName(), "Kappa", e);
                    }
                }
            }
            myWebView
                .loadDataWithBaseURL("file:///android_asset/", stringBuilder.toString(), "text/html", "utf-8", null);
        }
        else
        {
            myWebView.restoreState(WebViewStateHolder.INSTANCE.getBundle());
        }
        return rootView;
    }
}

Ho creato un supporto Singleton per lo stato di WebView. Lo stato viene conservato finché esiste il processo dell'applicazione.

EDIT: Non loadDataWithBaseURLera necessario, ha funzionato altrettanto bene con solo

    //in onCreate() for Activity, or in onCreateView() for Fragment

    if(WebViewStateHolder.INSTANCE.getBundle() == null) {
        webView.loadUrl("file:///android_asset/html/merged.html");
    } else {
        webView.restoreState(WebViewStateHolder.INSTANCE.getBundle());
    }

Anche se ho letto questo non funziona necessariamente bene con i cookie.


L'uso di singleton è problematico, in quanto presuppone che sia necessario utilizzare solo un'istanza.
Sviluppatore Android

@androiddeveloper ah. Bene, se non è vero nel tuo caso, allora in effetti è un problema. Ho avuto solo un'istanza di WebView, quindi questa domanda non mi è nemmeno venuta in mente.
EpicPandaForce

1

prova questo

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {

    private WebView wv;

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

        wv = (WebView) findViewById(R.id.webView);
        String url = "https://www.google.ps/";

        if (savedInstanceState != null)
            wv.restoreState(savedInstanceState);
        else {
            wv.setWebViewClient(new MyBrowser());
            wv.getSettings().setLoadsImagesAutomatically(true);
            wv.getSettings().setJavaScriptEnabled(true);
            wv.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
            wv.loadUrl(url);
        }
    }

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

    @Override
    public void onBackPressed() {
        if (wv.canGoBack())
            wv.goBack();
        else
            super.onBackPressed();
    }

    private class MyBrowser extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }

}

0

Questa pagina risolve il mio problema ma devo apportare una leggera modifica a quella iniziale:

    protected void onSaveInstanceState(Bundle outState) {
       webView.saveState(outState);
       }

Questa parte ha un leggero problema per me questo. Al secondo orientamento modificare l'applicazione terminata con puntatore null

usando questo ha funzionato per me:

    @Override
protected void onSaveInstanceState(Bundle outState ){
    ((WebView) findViewById(R.id.webview)).saveState(outState);
}

sembra essere esattamente lo stesso. Perché il secondo dovrebbe funzionare mentre il precedente no?
Sviluppatore Android

0

Dovresti provare questo:

  1. Crea un servizio, all'interno di quel servizio, crea il tuo WebView.
  2. Avvia il servizio dalla tua attività e associa ad esso.
  3. Nel onServiceConnectedmetodo, ottenere WebView e chiamare il setContentViewmetodo per eseguire il rendering di WebView.

L'ho provato e funziona ma non con altre visualizzazioni Web come XWalkView o GeckoView.


Ciao! Potresti spiegarlo di più? Grazie
Jaco,

1
Bene, ottieni la tua istanza di webview da Attività e prova a fare riferimento a un servizio in esecuzione in background. Alla successiva apertura di tale attività, provare innanzitutto a ottenere la visualizzazione Web salvata e renderla.
Ramdane Oualitsen,

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

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

Potresti aggiungere alcune righe di spiegazione alla tua risposta?
yacc,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.