Android WebView: manejo de cambios de orientación

147

El problema es el rendimiento después de la rotación. WebView tiene que volver a cargar la página, lo que puede ser un poco tedioso.

¿Cuál es la mejor manera de manejar un cambio de orientación sin volver a cargar la página desde el origen cada vez?

glennanthonyb
fuente
3
Por "recargar desde la fuente", ¿quiere decir que está descargando la página nuevamente, o simplemente volviéndola a procesar?
Jeremy Logan
La solución a la que hace referencia Blackhex resolvió mi problema.
Italo Borssatto
66
Me pregunto qué demonios tiene de especial mi aplicación que ninguna de estas respuestas trabajo ...
RobinJ

Respuestas:

91

Si no desea que WebView se vuelva a cargar en los cambios de orientación, simplemente anule onConfigurationChanged en su clase de Actividad:

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

Y configure el atributo android: configChanges en el manifiesto:

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

Para obtener más información, consulte:
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

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

Totach
fuente
44
Probé pero descubrí que no funciona, establecer el atributo configChanges como a continuación funcionará. android: configChanges = "keyboardHidden | orientación"
virsir
18
de hecho, esto se desaconseja, como se ha mencionado muchas veces antes
Matthias, el
3
Matthias: Esto no es realmente cierto; consulte Javadoc para WebView.
krtek
Dos cosas a tener en cuenta sobre esta solución: 1) Si tiene una Actividad abstracta con un WebView, el configChangesatributo se agrega a la subclase Actividad 2) Si su aplicación depende de múltiples proyectos, el configChangesatributo se agrega al manifiesto del que está en el parte superior del árbol de dependencias (que puede no ser el proyecto que contiene la clase Actividad).
Amanda S
44
Tal onConfigurationChangedanulación de método es inútil.
Miha_x64
69

Editar: este método ya no funciona como se indica en los documentos


Respuesta original:

Esto se puede manejar sobrescribiendo onSaveInstanceState(Bundle outState)su actividad y llamando saveStatedesde la vista web:

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

Luego recupere esto en su onCreate después de que la vista web se haya vuelto a inflar, por supuesto:

public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.blah);
   if (savedInstanceState != null)
      ((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
KWright
fuente
26
Esto no funciona en el cambio de orientación: se muestra una pantalla en blanco. Se llaman métodos saveState \ restoreState pero no ayuda.
Oleksii Malovanyi
1
Aquí está el fragmento de código onCreate: setContentView (R.layout.webview); mWebView = (WebView) findViewById (R.id.webview); if (savedInstanceState == null) {mWebView.getSettings (). setJavaScriptEnabled (true); mWebView.setWebViewClient (nuevo SimpleWebViewClient ()); mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } else {mWebView.restoreState (savedInstanceState); }
Oleksii Malovanyi
12
De la documentación de saveState: Tenga en cuenta que este método ya no almacena los datos de visualización para este WebView. El comportamiento anterior podría potencialmente filtrar archivos ...
brillenheini
55
"Tenga en cuenta que este método ya no almacena los datos de visualización para este WebView" - developer.android.com/reference/android/webkit/WebView.html
Steven Mark Ford
¿Alguien tiene alguna sugerencia sobre qué hacer ahora que "este método ya no almacena los datos de visualización para este WebView" para evitar la recarga de un formulario WebView?
Lucas P.
24

La mejor respuesta a esto es seguir la documentación de Android que se encuentra aquí. Básicamente, esto evitará que Webview se vuelva a cargar:

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

Opcionalmente , puede corregir anomalías (si las hay) anulando onConfigurationChangedla actividad:

@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();
    }
}
Tinashe
fuente
66
No necesita el método onConfigurationChanged (). Estoy bastante seguro, solo el atributo adicional en el Manifiesto. Supongo que WebView proporcionó soporte nativo para esto, y esta es la razón por la cual esta respuesta ahora es la mejor (porque esto no funcionó cuando se hizo la pregunta originalmente)
Booger
1
Apruebo @Booger, no necesita anular el método onConfigurationChanged (). Todo lo que necesita es agregar android: configChanges = "oriente | screenSize" en el archivo manifest.xml.
ozanurkan
5

Intenté usar onRetainNonConfigurationInstance (devolver el WebView ) y luego recuperarlo con getLastNonConfigurationInstance durante onCreate y reasignarlo.

Parece que aún no funciona. Sin embargo, no puedo evitar pensar que estoy muy cerca. Hasta ahora, acabo de obtener un WebView en blanco / fondo blanco en . Publicar aquí con la esperanza de que alguien pueda ayudar a superar esta meta.

Quizás no debería pasar el WebView . Quizás un objeto desde dentro de WebView ?

El otro método que probé, no es mi favorito, es configurar esto en la actividad:

 android:configChanges="keyboardHidden|orientation"

... y luego no hago casi nada aquí:

@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.
}

ESO funciona, pero podría no considerarse una mejor práctica .

Mientras tanto, también tengo un único ImageView que quiero actualizar automáticamente según la rotación. Esto resulta ser muy fácil. Debajo de mi rescarpeta, tengo drawable-landy tengo drawable-portvariaciones de paisaje / retrato, luego las uso R.drawable.myimagenamepara la fuente de ImageView y Android "hace lo correcto" - ¡sí!

... excepto cuando observa cambios de configuración, entonces no lo hace. :(

Entonces estoy en desacuerdo. Use onRetainNonConfigurationInstance y la rotación ImageView funciona, pero la persistencia de WebView no ... o use onConfigurationChanged y WebView se mantiene estable, pero ImageView no se actualiza. ¿Qué hacer?

Una última nota: en mi caso, forzar la orientación no es un compromiso aceptable. Realmente queremos apoyar con gracia la rotación. ¡Un poco como lo hace la aplicación del navegador de Android! ;)

Joe D'Andrea
fuente
77
No debe devolver ninguna vista de onRetainNonConfigurationInstance. Las vistas se adjuntan al Contexto de actividad, por lo que si guarda la vista, transporta todo ese equipaje cada vez que hay un cambio de orientación. La vista está "filtrada". (Consulte el último párrafo aquí: developer.android.com/resources/articles/… ) La mejor práctica para onRetainNonConfigurationInstance es guardar los datos que necesita la vista, no la vista en sí.
Declan Shanaghy
3

Un compromiso es evitar la rotación. Agregue esto para corregir la actividad solo para orientación vertical.

android:screenOrientation="portrait"
Jacques René Mesrine
fuente
Esto realmente funciona en muchos casos y es la solución que he decidido implementar :-)
Abdo
1
jeje, este es un cambio de requisito
Max Ch
3

La mejor manera de manejar los cambios de orientación y evitar la recarga de WebView en Rotate.

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

Con eso en mente, para evitar que se llame a onCreate () cada vez que cambie de orientación, deberá agregar android:configChanges="orientation|screenSize" to the AndroidManifest.

o solo ..

android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"`
Amit raj
fuente
3

Simplemente escriba las siguientes líneas de código en su archivo de Manifiesto, nada más. Realmente funciona:

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

Aprecio que esto sea un poco tarde, sin embargo, esta es la respuesta que utilicé al desarrollar mi solución:

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

}
David Passmore
fuente
2

Puede intentar usar onSaveInstanceState()y onRestoreInstanceState()en su Actividad para llamar saveState(...)y restoreState(...)en su instancia de WebView.

deltaearl
fuente
2

Es 2015, y muchas personas están buscando una solución que todavía funcione en teléfonos Jellybean, KK y Lollipop. Después de mucho esfuerzo, encontré una manera de preservar la vista web intacta después de cambiar la orientación. Mi estrategia es básicamente almacenar la vista web en una variable estática separada en otra clase. Luego, si se produce rotación, desconecto la vista web de la actividad, espero a que termine la orientación y vuelvo a conectar la vista web a la actividad. Por ejemplo ... primero ponga esto en su MANIFEST (keyboardHidden y keyboard son opcionales):

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

En una CLASE DE APLICACIÓN SEPARADA, ponga:

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

En la ACTIVIDAD poner:

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

Finalmente, el XML simple:

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

Hay varias cosas que podrían mejorarse en mi solución, pero ya pasé mucho tiempo, por ejemplo: una forma más corta de validar si la Actividad se inició por primera vez en lugar de usar el almacenamiento de Preferencias Compartidas. Este enfoque conserva su vista web intacta (afaik), sus cuadros de texto, etiquetas, IU, variables de JavaScript y estados de navegación que no se reflejan en la URL.

Josh
fuente
1
¿Por qué incluso molestarse en desconectar y volver a conectar el WebView cuando nunca se destruye, ya que maneja manualmente los cambios de configuración?
Fred
@Fred Porque quiero mantener intacto el estado exacto de la vista web y su contenido, incluidas las cookies, y el estado de los botones y casillas de verificación implementados con HTML5 o JS dentro de la página web cargada por la vista web. El único ajuste que hago es cambiar el tamaño.
Josh el
Fred significaba que no era necesario separar / volver a conectar la vista web a través de una clase estática como declaraste configChanges en el manifiesto. De esta manera, sus vistas y actividad no se destruyen durante la rotación en ningún caso.
Eugene Kartoyev
2

Lo único que debe hacer es agregar este código a su archivo de manifiesto:

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

Actualización: la estrategia actual es mover la instancia de WebView a la clase Aplicación en lugar del fragmento retenido cuando se separa y volver a colocar en el currículum como lo hace Josh. Para evitar que la aplicación se cierre, debe usar el servicio en primer plano, si desea conservar el estado cuando el usuario cambia de una aplicación a otra.

Si está utilizando fragmentos, puede usar la instancia de retención de WebView. La vista web se conservará como miembro de instancia de la clase. Sin embargo, debe adjuntar la vista web en OnCreateView y desconectarla antes de OnDestroyView para evitar que se destruya con el contenedor principal.

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

PD Créditos ir a kcoppock respuesta

En cuanto a 'SaveState ()' ya no funciona de acuerdo con la documentación oficial :

Tenga en cuenta que este método ya no almacena los datos de visualización para este WebView. El comportamiento anterior podría potencialmente filtrar archivos si no se llama a restoreState (Bundle).

revs Boris Treukhov
fuente
Tenga en cuenta que si bien setRetainInstanceconserva el Fragmento, la vista (y, por lo tanto, la Vista web) aún se destruye.
Fred
1
@ Fred ¿Puede proporcionar una fuente para esa declaración? He probado esto en una pequeña aplicación que tiene un fragmento con setRetainInstance (verdadero) que muestra una página de youtube y si cambio la orientación, la vista parece conservarse ya que el video no se interrumpe. No parece que la vista web se esté destruyendo.
Pinkerton
@Rai Fue solo una mala lectura, he editado un poco la respuesta desde entonces (todavía necesita algunas correcciones de redacción). Si está interesado en el estado actual de las cosas, este método funciona. Sin embargo, el problema es que Android mata la aplicación cuando tiene poca memoria. Tengo un formulario de entrada importante donde el usuario tiene que leer un mensaje en otra aplicación, por lo que tuve que usar el servicio en primer plano con notificación para evitar que el proceso se bloquee. Sin embargo, Android aún destruye la actividad y, por lo tanto, el marco retenido. Pero la instancia de la clase Aplicación se conserva, por lo que ahora muevo WebView a la Aplicación.
Boris Treukhov
1
También uso MutableContextWrapper como base de WebView, cambio contextos a actividades en adjuntar y desconectar. Otro gran problema que los controles de zoom incorporados de Chromium guardan referencia a la actividad anterior, por lo que no hay solución de zoom con WebView adjunto a la aplicación en lugar de actividad. TL; DR; si su formulario no es tan importante, y puede vivir con el hecho de que después del cambio de aplicación, su proceso puede ser cancelado y la vista web no restaurada, vaya con la solución de marco retenido. PD: también creo que los empleados de Google están lejos, lejos de los problemas de la vida real con todos sus widgets-gadgets ...
Boris Treukhov
1
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);    
}

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

Estos métodos se pueden anular en cualquier actividad, básicamente solo le permite guardar y restaurar valores cada vez que se crea / destruye una actividad, cuando la orientación de la pantalla cambia, la actividad se destruye y se recrea en segundo plano, por lo que podría usar estos métodos almacenar temporalmente / restaurar estados durante el cambio.

Debe tener una mirada más profunda a los dos métodos siguientes y ver si se ajusta a su solución.

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

Chiwai Chan
fuente
1

Esto es lo único que funcionó para mí (incluso utilicé el estado de guardar instancia onCreateViewpero no fue tan confiable).

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

Hice un titular Singleton para el estado de WebView. El estado se conserva mientras exista el proceso de la aplicación.

EDITAR: No loadDataWithBaseURLfue necesario, funcionó tan bien 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());
    }

Aunque leí esto, no necesariamente funciona bien con las cookies.

EpicPandaForce
fuente
El uso de singleton es problemático, ya que supone que solo tiene una instancia que necesita usar.
Desarrollador de Android
@androiddeveloper ah. Bueno, si eso no es cierto en su caso, entonces sí que es un problema. Solo tenía una instancia de WebView, por lo que esta pregunta ni siquiera se me ocurrió.
EpicPandaForce
1

prueba esto

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

}
Anwar SE
fuente
0

Esta página resuelve mi problema, pero tengo que hacer un ligero cambio en la inicial:

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

Esta porción tiene un pequeño problema para mí esto. En la segunda orientación, cambie la aplicación terminada con un puntero nulo

usando esto funcionó para mí:

    @Override
protected void onSaveInstanceState(Bundle outState ){
    ((WebView) findViewById(R.id.webview)).saveState(outState);
}
gyanu
fuente
Parece ser exactamente lo mismo. ¿Por qué el segundo funcionaría mientras que el anterior no?
Desarrollador de Android
0

Deberías probar esto:

  1. Cree un servicio, dentro de ese servicio, cree su WebView.
  2. Inicia el servicio desde tu actividad y únete a él.
  3. En el onServiceConnectedmétodo, obtenga el WebView y llame al setContentViewmétodo para representar su WebView.

Lo probé y funciona, pero no con otros WebViews como XWalkView o GeckoView.

Ramdane Oualitsen
fuente
¡Hola! ¿Podrías explicarlo más? Gracias
Jaco
1
Bueno, obtenga su instancia de vista web desde su Actividad e intente hacer referencia a un servicio que se ejecuta en segundo plano. La próxima vez que abra esa actividad, intente obtener primero la vista web guardada y renderizarla.
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);
    }
RealDEV
fuente
¿Podría agregar algunas líneas de explicación a su respuesta?
yacc