Android WebView: lidando com alterações de orientação

147

O problema é o desempenho após a rotação. O WebView precisa recarregar a página, o que pode ser um pouco entediante.

Qual é a melhor maneira de lidar com uma mudança de orientação sem recarregar a página da fonte toda vez?

glennanthonyb
fonte
3
Ao "recarregar a partir do código-fonte", você quer dizer que está baixando a página novamente ou apenas a renderizando novamente?
Jeremy Logan
A solução referenciada pela Blackhex resolveu meu problema.
Italo Borssatto 19/09/12
6
Eu me pergunto o que diabos há de tão especial sobre o meu app que nenhuma dessas respostas trabalho ...
RobinJ

Respostas:

91

Se você não deseja que o WebView seja recarregado com alterações de orientação, substitua onConfigurationChanged na sua classe Activity:

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

E defina o atributo android: configChanges no manifesto:

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

para obter mais informações, consulte:
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

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

Totach
fonte
4
Eu testei, mas encontrei não funciona, configure o atributo configChanges como abaixo funcionará. android: configChanges = "keyboardHidden | orientação"
virsir 27/02
18
fazer isso é de fato desencorajado, como já foi mencionado muitas vezes antes
Matthias
3
Matthias: Isso não é verdade - consulte Javadoc para WebView.
krtek
Duas coisas a serem observadas sobre esta solução: 1) Se você tiver uma atividade abstrata com um WebView, o configChangesatributo será adicionado à subclasse. Atividade 2) Se seu aplicativo depender de vários projetos, o configChangesatributo será adicionado ao manifesto daquele no topo da árvore de dependência (que pode não ser o projeto que contém a classe Activity).
21711 Amanda S
4
Essa onConfigurationChangedsubstituição de método é inútil.
Miha_x64
69

Editar: este método não funciona mais como indicado nos documentos


Resposta original:

Isso pode ser tratado sobrescrevendo onSaveInstanceState(Bundle outState)sua atividade e chamando a saveStatepartir da visualização na web :

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

Em seguida, recupere isso no seu onCreate depois que a visualização na web tiver sido inflada novamente, é claro:

public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.blah);
   if (savedInstanceState != null)
      ((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
KWright
fonte
26
Isso não funciona na mudança de orientação - a tela em branco é exibida. Os métodos saveState \ restoreState são chamados, mas isso não ajuda.
9789 Oleksii Malovanyi #
1
Aqui está o trecho de código onCreate: setContentView (R.layout.webview); mWebView = (WebView) findViewById (R.id.webview); if (savedInstanceState == null) {mWebView.getSettings (). setJavaScriptEnabled (true); mWebView.setWebViewClient (novo SimpleWebViewClient ()); mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } else {mWebView.restoreState (savedInstanceState); }
Oleksii Malovanyi 9/11
12
Na documentação de saveState: Observe que esse método não armazena mais os dados de exibição para este WebView. O comportamento anterior pode vazar arquivos ...
brillenheini 25/06
5
"Observe que esse método não armazena mais os dados de exibição para este WebView" - developer.android.com/reference/android/webkit/WebView.html
Steven Mark Ford
Alguém tem alguma sugestão sobre o que fazer agora que "esse método não armazena mais os dados de exibição deste WebView" para impedir que um formulário do WebView seja recarregado?
Lucas P.
24

A melhor resposta para isso é seguir a documentação do Android encontrada aqui Basicamente, isso impedirá o recarregamento do Webview:

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

Opcionalmente , você pode corrigir anomalias (se houver) substituindo onConfigurationChangedna atividade:

@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
fonte
6
Você não precisa do método onConfigurationChanged (), tenho certeza, apenas do atributo adicional no manifesto. Meu palpite é que o suporte nativo para este foi fornecido pelo WebView, e é por isso que esta resposta é agora o melhor (porque isso não funcionou quando a questão foi originalmente solicitado)
Booger
1
Eu aprovo o @Booger, você não precisa substituir o método onConfigurationChanged (). Tudo o que você precisa é adicionar android: configChanges = "orientação | screenSize" no arquivo manifest.xml.
ozanurkan
5

Tentei usar onRetainNonConfigurationInstance (retornando o WebView ) e recuperá-lo com getLastNonConfigurationInstance durante onCreate e redesigná-lo.

Ainda não parece funcionar. Eu não posso ajudar, mas acho que estou realmente perto! Até agora, recebi apenas um WebView em branco / fundo branco em . Postando aqui na esperança de que alguém possa ajudar a empurrar este além da linha de chegada.

Talvez eu não devesse estar passando no WebView . Talvez um objeto do WebView ?

O outro método que tentei - não o meu favorito - é definir isso na atividade:

 android:configChanges="keyboardHidden|orientation"

... e não faça praticamente nada aqui:

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

Isso funciona, mas pode não ser considerado uma prática recomendada .

Enquanto isso, também tenho um único ImageView que quero atualizar automaticamente, dependendo da rotação. Isso acaba sendo muito fácil. Na minha respasta, tenho drawable-lande drawable-portmantenha variações de paisagem / retrato, depois uso R.drawable.myimagenamea fonte do ImageView e o Android "faz a coisa certa" - sim!

... exceto quando você observa mudanças na configuração, isso não acontece. :(

Então, eu estou em desacordo. Use onRetainNonConfigurationInstance e a rotação do ImageView funciona, mas a persistência do WebView não ... ou use onConfigurationChanged e o WebView permanece estável, mas o ImageView não é atualizado. O que fazer?

Uma última observação: no meu caso, forçar a orientação não é um compromisso aceitável. Nós realmente queremos apoiar graciosamente a rotação. Mais ou menos como o aplicativo do Navegador Android funciona! ;)

Joe D'Andrea
fonte
7
Você não deve retornar nenhuma vista de onRetainNonConfigurationInstance. As visualizações são anexadas ao Contexto de Atividade, portanto, se você salvar a visualização, carregará toda essa bagagem toda vez que houver uma mudança de orientação. A vista está "vazada". (Consulte o último parágrafo aqui: developer.android.com/resources/articles/… ) A melhor prática para onRetainNonConfigurationInstance é salvar os dados de que a exibição precisa, não a exibição em si.
Declan Shanaghy
3

Um compromisso é evitar a rotação. Adicione isso para corrigir a atividade apenas na orientação Retrato.

android:screenOrientation="portrait"
Jacques René Mesrine
fonte
Isso realmente funciona em muitos casos e é a solução decidi implementar :-)
Abdo
1
hehe, esta é uma mudança exigência
Max Ch
3

A melhor maneira de lidar com alterações de orientação e impedir a recarga do WebView no Rotate.

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

Com isso em mente, para impedir que onCreate () seja chamado toda vez que você altera a orientação, é necessário adicionar android:configChanges="orientation|screenSize" to the AndroidManifest.

ou apenas ..

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

Basta escrever as seguintes linhas de código no seu arquivo de manifesto - nada mais. Realmente funciona:

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

Compreendo que isso seja um pouco tarde, no entanto, esta é a resposta que eu usei ao desenvolver minha solução:

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

Você pode tentar usar onSaveInstanceState()e onRestoreInstanceState()em sua Atividade para ligar saveState(...)e restoreState(...)em sua instância do WebView.

deltaearl
fonte
2

É 2015, e muitas pessoas estão procurando uma solução que ainda funcione nos telefones Jellybean, KK e Lollipop. Depois de muita luta, encontrei uma maneira de preservar intacta a visualização na web depois que você altera a orientação. Minha estratégia é basicamente armazenar a visualização da web em uma variável estática separada em outra classe. Em seguida, se ocorrer rotação, desanexo a visualização da web da atividade, espero a conclusão da orientação e reconecto a visualização da web à atividade. Por exemplo ... primeiro coloque isso no seu MANIFEST (keyboardHidden e teclado são opcionais):

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

Em uma CLASSE DE APLICAÇÃO SEPARADA, coloque:

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

Em ACTIVITY coloque:

@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, o XML simples:

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

Há várias coisas que podem ser aprimoradas em minha solução, mas eu já gastei muito tempo, por exemplo: uma maneira mais curta de validar se a Atividade foi iniciada pela primeira vez, em vez de usar o armazenamento SharedPreferences. Essa abordagem preserva a visualização na web intacta (afaik), suas caixas de texto, rótulos, interface do usuário, variáveis ​​javascript e estados de navegação que não são refletidos pelo URL.

Josh
fonte
1
Por que se preocupar em desconectar e reconectar o WebView quando ele nunca é destruído, desde que você lida manualmente com as alterações na configuração?
Fred
@Fred Porque eu quero manter intacto o estado exato da Webview e seu conteúdo, incluindo cookies, e o estado dos botões e caixas de seleção implementados com HTML5 ou JS dentro da página carregada pela Webview. O único ajuste que faço é redimensionar.
217 Josh Josh
Fred significava que você não precisa desanexar / reconectar a visualização da web por meio de uma classe estática, conforme declarou configChanges no manifesto. Dessa forma, suas visualizações e atividades não são destruídas durante a rotação, em nenhum caso.
Eugene Kartoyev 18/10/19
2

A única coisa que você deve fazer é adicionar esse código ao seu arquivo de manifesto:

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

Atualização: a estratégia atual é mover a instância do WebView para a classe Application, em vez de fragmento retido quando desanexado e reconectar no currículo, como Josh faz. Para impedir que o Aplicativo seja fechado, você deve usar o serviço em primeiro plano, se desejar manter o estado quando o usuário alternar entre aplicativos.

Se você estiver usando fragmentos, poderá usar a instância de retenção do WebView. A visualização da web será mantida como membro da instância da classe. No entanto, você deve anexar a exibição da Web no OnCreateView e desanexá-lo antes do OnDestroyView para impedir sua destruição com o contêiner pai.

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

Créditos PS: vá para a resposta do kcoppock

Quanto a 'SaveState ()', ele não funciona mais de acordo com a documentação oficial :

Observe que esse método não armazena mais os dados de exibição para este WebView. O comportamento anterior poderia vazar arquivos se o restoreState (Bundle) nunca fosse chamado.

Boris Treukhov
fonte
Observe que enquanto setRetainInstancemantém o fragmento, a exibição (e, portanto, o WebView) ainda é destruída.
Fred
1
@Fred Você pode fornecer uma fonte para essa declaração? Eu testei isso em um aplicativo pequeno que possui um fragmento com setRetainInstance (true) que exibe uma página do youtube e, se eu mudar a orientação, a exibição parecerá mantida, pois o vídeo não será interrompido. Não parece que a webview está sendo destruída.
Pinkerton
@ RAI Foi apenas uma leitura errada, editei um pouco a resposta desde então (ainda precisa de algumas correções de redação). Se você está interessado no estado atual das coisas - esse método funciona. No entanto, o problema é que o Android mata o aplicativo quando está com pouca memória. Eu tenho um formulário de entrada importante em que o usuário precisa ler uma mensagem em outro aplicativo; portanto, tive que usar o serviço de primeiro plano com notificação para impedir que o processo fosse morto. No entanto, o androide ainda destrói a atividade e, portanto, o quadro retido. Mas a instância da classe Application é preservada - então eu movo o WebView para Application agora.
Boris Treukhov
1
Também uso o MutableContextWrapper como base do WebView, alterno os contextos para as atividades de anexar e desanexar. Outro grande problema que o Chromium constrói nos controles de zoom salva a referência à atividade antiga, portanto, nenhuma solução de zoom com o WebView anexado ao Aplicativo em vez de Atividade. TL; DR; se o seu formulário não é tão importante e você pode conviver com o fato de que, após a troca do aplicativo, seu processo pode ser interrompido e a visualização da web não restaurada, acompanhada de uma solução de quadro retido. PS também penso que os funcionários do Google estão longe, longe de problemas da vida real, com todos os seus widgets de dispositivos ..
Boris Treukhov
1
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);    
}

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

Esses métodos podem ser substituídos em qualquer atividade, mas basicamente permitem salvar e restaurar valores toda vez que uma atividade é criada / destruída, quando a orientação da tela muda, a atividade é destruída e recriada em segundo plano; portanto, você pode usar esses métodos para armazenar / restaurar temporariamente os estados durante a alteração.

Você deve examinar mais profundamente os dois métodos a seguir e verificar se ele se encaixa na sua solução.

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

Chiwai Chan
fonte
1

A melhor solução que encontrei para fazer isso sem vazar a Activityreferência anterior e sem definir o configChanges.. é usar um MutableContextWrapper .

Eu implementei isso aqui: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java

Simon
fonte
isso funciona de forma confiável, sem efeitos colaterais? Não encontrei muita informação sobre esse método.
precisa saber é o seguinte
1

Essa é a única coisa que funcionou para mim (eu até usei o estado da instância de salvamento, onCreateViewmas não era tão confiável).

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

Fiz um titular Singleton para o estado do WebView. O estado é preservado enquanto o processo do aplicativo existir.

EDIT: O loadDataWithBaseURLnão era necessário, funcionou tão bem com apenas

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

Embora eu tenha lido isso, não necessariamente funciona bem com cookies.

EpicPandaForce
fonte
O uso do singleton é problemático, pois supõe que você tenha apenas uma instância que precisa usar.
desenvolvedor android
@androiddeveloper ah. Bem, se isso não for verdade no seu caso, então esse é realmente um problema. Eu só tinha uma instância do WebView, então essa pergunta nem me veio à tona.
EpicPandaForce
1

tente isso

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

Esta página resolve meu problema, mas preciso fazer pequenas alterações na inicial:

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

Esta parte tem um pequeno problema para mim isso. Na segunda orientação, altere o aplicativo finalizado com ponteiro nulo

usando isso funcionou para mim:

    @Override
protected void onSaveInstanceState(Bundle outState ){
    ((WebView) findViewById(R.id.webview)).saveState(outState);
}
gyanu
fonte
parece ser exatamente o mesmo. Por que o segundo funcionaria enquanto o anterior não?
desenvolvedor android
0

Você deve tentar o seguinte:

  1. Crie um serviço, dentro desse serviço, crie seu WebView.
  2. Inicie o serviço de sua atividade e vincule-o.
  3. No onServiceConnectedmétodo, obtenha o WebView e chame o setContentViewmétodo para renderizar seu WebView.

Eu testei e funciona, mas não com outros WebViews como XWalkView ou GeckoView.

Ramdane Oualitsen
fonte
Oi! Você poderia explicar mais? Obrigado
Jaco
1
Bem, instale sua instância de visualização da web em Activity e tente refazer um serviço em execução em segundo plano. Na próxima vez que você abrir essa atividade, tente primeiro obter a visualização da web salva e renderizá-la.
Ramdane Oualitsen 18/11/19
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
fonte
Você poderia adicionar algumas linhas de explicação à sua resposta?
yacc
-1

Eu gosto desta solução http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

Segundo ele, reutilizamos a mesma instância do WebView. Permite salvar o histórico de navegação e rolar a posição na alteração da configuração.

Taras Shevchuk
fonte
O link acima leva a uma página que não pode ser visualizada sem a instalação de algum 'plugin de segurança'; evitar.
Allan Bazinet