Android WebView: Umgang mit Orientierungsänderungen

147

Das Problem ist die Leistung nach der Rotation. Das WebView muss die Seite neu laden, was etwas mühsam sein kann.

Was ist der beste Weg, um eine Orientierungsänderung zu handhaben, ohne die Seite jedes Mal von der Quelle neu zu laden?

Glennanthonyb
quelle
3
Mit "Aus dem Quellcode neu laden" meinen Sie, dass die Seite erneut heruntergeladen oder nur neu gerendert wird?
Jeremy Logan
Die von Blackhex referenzierte Lösung löste mein Problem.
Italo Borssatto
6
Ich frage mich, was zum Teufel an meiner App so besonders ist, dass keine dieser Antworten funktioniert ...
RobinJ

Antworten:

91

Wenn Sie nicht möchten, dass WebView bei Änderungen der Ausrichtung neu geladen wird, überschreiben Sie einfach onConfigurationChanged in Ihrer Aktivitätsklasse:

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

Und setzen Sie das Attribut android: configChanges im Manifest:

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

Weitere Informationen finden Sie unter:
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

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

Totach
quelle
4
Ich habe getestet, aber festgestellt, dass es nicht funktioniert. Setzen Sie das configChanges-Attribut wie unten. android: configChanges = "keyboardHidden | orientierung"
virsir
18
Dies zu tun ist in der Tat entmutigt, wie schon oft erwähnt wurde
Matthias
3
Matthias: Das stimmt nicht wirklich - siehe Javadoc für WebView.
krtek
Zwei Dinge, die Sie bei dieser Lösung beachten sollten: 1) Wenn Sie eine abstrakte Aktivität mit einer WebView haben, wird das configChangesAttribut der Unterklasse hinzugefügt. Aktivität 2) Wenn Ihre App von mehreren Projekten abhängt, wird das configChangesAttribut dem Manifest des Projekts am hinzugefügt oben im Abhängigkeitsbaum (möglicherweise nicht das Projekt, das die Aktivitätsklasse enthält).
Amanda S
4
Eine solche onConfigurationChangedMethodenüberschreibung ist nutzlos.
Miha_x64
69

Bearbeiten: Diese Methode funktioniert nicht mehr wie in den Dokumenten angegeben


Ursprüngliche Antwort:

Dies kann durch Überschreiben onSaveInstanceState(Bundle outState)Ihrer Aktivität und Aufrufen saveStateaus der Webansicht erfolgen:

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

Stellen Sie dies dann in Ihrem onCreate wieder her, nachdem die Webansicht natürlich wieder aufgeblasen wurde:

public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.blah);
   if (savedInstanceState != null)
      ((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
KWright
quelle
26
Dies funktioniert bei Orientierungsänderungen nicht - der leere Bildschirm wird angezeigt. saveState \ restoreState-Methoden werden aufgerufen, aber es hilft nicht.
Oleksii Malovanyi
1
Hier ist das Code-Snippet onCreate: setContentView (R.layout.webview); mWebView = (WebView) findViewById (R.id.webview); if (savedInstanceState == null) {mWebView.getSettings (). setJavaScriptEnabled (true); mWebView.setWebViewClient (neuer SimpleWebViewClient ()); mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } else {mWebView.restoreState (savedInstanceState); }
Oleksii Malovanyi
12
Aus der Dokumentation von saveState: Bitte beachten Sie, dass diese Methode die Anzeigedaten für diese WebView nicht mehr speichert. Das vorherige Verhalten könnte möglicherweise Dateien lecken ...
brillenheini
5
"Bitte beachten Sie, dass diese Methode die Anzeigedaten für dieses WebView nicht mehr speichert" - developer.android.com/reference/android/webkit/WebView.html
Steven Mark Ford
Hat jemand einen Vorschlag, was jetzt zu tun ist, da "diese Methode die Anzeigedaten für dieses WebView nicht mehr speichert", um ein erneutes Laden eines WebView-Formulars zu verhindern?
Lucas P.
24

Die beste Antwort darauf ist die folgende Android-Dokumentation, die hier zu finden ist. Grundsätzlich verhindert dies, dass Webview neu geladen wird:

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

Optional können Sie Anomalien (falls vorhanden) beheben, indem Sie onConfigurationChangeddie Aktivität überschreiben :

@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
quelle
6
Ich bin mir ziemlich sicher, dass Sie die onConfigurationChanged () -Methode nicht benötigen, sondern nur das zusätzliche Attribut im Manifest. Ich vermute, dass die native Unterstützung dafür von WebView bereitgestellt wurde, und aus diesem Grund ist diese Antwort jetzt die beste (da dies nicht funktionierte, als die Frage ursprünglich gestellt wurde)
Booger
1
Ich genehmige @Booger, dass Sie die onConfigurationChanged () -Methode nicht überschreiben müssen. Sie müssen lediglich android: configChanges = "Orientierung | Bildschirmgröße" in der Datei manifest.xml hinzufügen.
Ozanurkan
5

Ich habe versucht, onRetainNonConfigurationInstance zu verwenden (das WebView zurückzugeben ), es dann mit getLastNonConfigurationInstance während onCreate zurückzugewinnen und neu zuzuweisen .

Scheint noch nicht zu funktionieren. Ich kann nicht anders als zu denken, dass ich wirklich nah dran bin! Bisher bekomme ich stattdessen nur ein WebView mit leerem / weißem Hintergrund . Poste hier in der Hoffnung, dass jemand helfen kann, diesen über die Ziellinie zu schieben.

Vielleicht sollte ich das WebView nicht weitergeben . Möglicherweise ein Objekt aus dem WebView ?

Die andere Methode, die ich ausprobiert habe - nicht meine Lieblingsmethode - besteht darin, dies in der Aktivität festzulegen:

 android:configChanges="keyboardHidden|orientation"

... und dann so ziemlich nichts hier machen:

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

DAS funktioniert, aber es kann nicht als Best Practice angesehen werden .

Mittlerweile habe ich auch eine einzelne ImageView , die ich je nach Rotation automatisch aktualisieren möchte. Dies stellt sich als sehr einfach heraus. Unter meinem resOrdner habe drawable-landund drawable-porthalte ich Quer- / Hochformatvarianten, die ich dann R.drawable.myimagenamefür die ImageView verwende -Quelle und Android "macht das Richtige" - yay!

... außer wenn Sie auf Konfigurationsänderungen achten, dann nicht. :((

Also bin ich uneins. Verwenden Sie onRetainNonConfigurationInstance und die ImageView- Rotation funktioniert, aber die WebView- Persistenz funktioniert nicht ... oder verwenden Sie onConfigurationChanged und die WebView bleibt stabil, aber die ImageView wird nicht aktualisiert. Was ist zu tun?

Ein letzter Hinweis: In meinem Fall ist das Erzwingen der Orientierung kein akzeptabler Kompromiss. Wir möchten die Rotation wirklich elegant unterstützen. Ein bisschen wie die Android Browser App! ;)

Joe D'Andrea
quelle
7
Sie sollten keine Ansichten von onRetainNonConfigurationInstance zurückgeben. Die Ansichten sind an den Aktivitätskontext angehängt. Wenn Sie also die Ansicht speichern, übertragen Sie jedes Mal, wenn sich die Ausrichtung ändert, das gesamte Gepäck. Die Ansicht ist "durchgesickert". (Siehe letzten Absatz hier: developer.android.com/resources/articles/… ) Die beste Vorgehensweise für onRetainNonConfigurationInstance besteht darin, die Daten zu speichern, die die Ansicht benötigt, nicht die Ansicht selbst.
Declan Shanaghy
3

Ein Kompromiss besteht darin, eine Rotation zu vermeiden. Fügen Sie dies hinzu, um die Aktivität nur für die Porträtausrichtung zu korrigieren.

android:screenOrientation="portrait"
Jacques René Mesrine
quelle
Dies funktioniert tatsächlich in vielen Fällen und ist die Lösung, für die ich mich entschieden habe :-)
Abdo
1
hehe, das ist eine Anforderungsänderung
Max Ch
3

Der beste Weg, um Orientierungsänderungen zu handhaben und das erneute Laden von WebView beim Drehen zu verhindern.

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

Um zu verhindern, dass onCreate () jedes Mal aufgerufen wird, wenn Sie die Ausrichtung ändern, müssen Sie hinzufügen android:configChanges="orientation|screenSize" to the AndroidManifest.

oder nur ..

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

Schreiben Sie einfach die folgenden Codezeilen in Ihre Manifest-Datei - sonst nichts. Es funktioniert wirklich:

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

Ich schätze, dass dies etwas spät ist, aber dies ist die Antwort, die ich bei der Entwicklung meiner Lösung verwendet habe:

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

Sie können mit Hilfe versuchen onSaveInstanceState()und onRestoreInstanceState()auf Ihrer Aktivität zu nennen saveState(...)und restoreState(...)auf Ihrer WebView - Instanz.

Deltaearl
quelle
2

Es ist 2015 und viele Menschen suchen nach einer Lösung, die immer noch auf Jellybean-, KK- und Lollipop-Telefonen funktioniert. Nach vielem kämpfen , fand ich einen Weg , um die Webansicht intakt zu erhalten , nachdem Sie Orientierung ändern. Meine Strategie besteht im Wesentlichen darin, die Webansicht in einer separaten statischen Variablen in einer anderen Klasse zu speichern. Wenn dann eine Drehung auftritt, entferne ich die Webansicht von der Aktivität, warte, bis die Ausrichtung abgeschlossen ist, und füge die Webansicht wieder der Aktivität hinzu. Zum Beispiel ... setzen Sie dies zuerst auf Ihr MANIFEST (KeyboardHidden und Keyboard sind optional):

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

Geben Sie in einer SEPARATEN ANWENDUNGSKLASSE Folgendes ein:

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

In die AKTIVITÄT setzen:

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

Zum Schluss das einfache 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>

Es gibt einige Dinge, die in meiner Lösung verbessert werden könnten, aber ich habe bereits zu viel Zeit aufgewendet, zum Beispiel: eine kürzere Methode, um zu überprüfen, ob die Aktivität zum ersten Mal gestartet wurde, anstatt den SharedPreferences-Speicher zu verwenden. Bei diesem Ansatz bleiben die Webansicht (afaik), ihre Textfelder, Beschriftungen, Benutzeroberflächen, Javascript-Variablen und Navigationszustände erhalten, die nicht in der URL wiedergegeben werden.

Josh
quelle
1
Warum sollten Sie sich überhaupt die Mühe machen, das WebView zu trennen und wieder anzuschließen, wenn es überhaupt nicht zerstört wird, da Sie Konfigurationsänderungen manuell bearbeiten?
Fred
@Fred Weil ich den genauen Status der Webansicht und ihres Inhalts, einschließlich Cookies, sowie den Status der Schaltflächen und Kontrollkästchen, die mit HTML5 oder JS in der von der Webansicht geladenen Webseite implementiert sind, beibehalten möchte. Die einzige Anpassung, die ich vornehme, ist die Größenänderung.
Josh
Fred meinte, Sie müssen die Webansicht nicht über eine statische Klasse trennen / erneut anhängen, da Sie configChanges im Manifest deklariert haben. Auf diese Weise werden Ihre Ansichten und Aktivitäten während der Rotation auf keinen Fall zerstört.
Eugene Kartoyev
2

Das einzige, was Sie tun sollten, ist diesen Code zu Ihrer Manifestdatei hinzuzufügen:

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

Update: Die aktuelle Strategie besteht darin, die WebView-Instanz in die Anwendungsklasse zu verschieben, anstatt das Fragment beizubehalten, wenn es getrennt wird, und beim Fortsetzen erneut anzuhängen, wie es Josh tut. Um zu verhindern, dass die Anwendung geschlossen wird, sollten Sie den Vordergrunddienst verwenden, wenn Sie den Status beibehalten möchten, wenn der Benutzer zwischen Anwendungen wechselt.

Wenn Sie Fragmente verwenden, können Sie die Instanz von WebView beibehalten verwenden. Die Webansicht bleibt als Instanzmitglied der Klasse erhalten. Sie sollten jedoch die Webansicht in OnCreateView anhängen und vor OnDestroyView trennen, um zu verhindern, dass sie mit dem übergeordneten Container zerstört wird.

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

PS Credits gehen an kcoppock Antwort

'SaveState ()' funktioniert laut offizieller Dokumentation nicht mehr :

Bitte beachten Sie, dass diese Methode die Anzeigedaten für diese WebView nicht mehr speichert. Das vorherige Verhalten kann möglicherweise Dateien verlieren, wenn restoreState (Bundle) nie aufgerufen wurde.

Boris Treukhov
quelle
Beachten Sie, dass setRetainInstancedie Ansicht (und damit die WebView) weiterhin zerstört wird , während das Fragment beibehalten wird.
Fred
1
@Fred Können Sie eine Quelle für diese Aussage angeben? Ich habe dies in einer kleinen App getestet, die ein Fragment mit setRetainInstance (true) enthält, das eine Youtube-Seite anzeigt. Wenn ich die Ausrichtung ändere, scheint die Ansicht beibehalten zu werden, da das Video nicht unterbrochen wird. Scheint nicht so, als würde die Webansicht zerstört.
Pinkerton
@ Rai Es war nur eine Fehlinterpretation, ich habe die Antwort seitdem ein bisschen bearbeitet (es braucht noch einige Wortlautkorrekturen). Wenn Sie sich für den aktuellen Stand der Dinge interessieren, funktioniert diese Methode. Das Problem ist jedoch, dass Android die Anwendung beendet, wenn der Arbeitsspeicher knapp ist. Ich habe ein wichtiges Eingabeformular, in dem der Benutzer eine Nachricht in einer anderen Anwendung lesen muss. Daher musste ich den Vordergrunddienst mit Benachrichtigung verwenden, um zu verhindern, dass der Prozess abgebrochen wird. Dennoch zerstört Android immer noch die Aktivität und damit den beibehaltenen Rahmen. Die Instanz der Anwendungsklasse bleibt jedoch erhalten. Daher verschiebe ich WebView jetzt in die Anwendung.
Boris Treukhov
1
Ich verwende auch MutableContextWrapper als Basis für WebView. Ich wechsle Kontexte zu Aktivitäten beim Anhängen und Trennen. Ein weiteres großes Problem, das in Chromium eingebaute Zoom-Steuerelemente den Verweis auf alte Aktivitäten speichern, ist also keine Vergrößerungslösung, bei der WebView anstelle von Aktivität an die Anwendung angehängt ist. TL; DR; Wenn Ihr Formular nicht so wichtig ist und Sie möglicherweise damit leben, dass nach dem App-Wechsel Ihr Prozess abgebrochen und die Webansicht nicht wiederhergestellt werden kann, verwenden Sie die beibehaltene Frame-Lösung. PS auch ich denke, dass Google-Mitarbeiter weit entfernt von realen Problemen mit all ihren Widgets-Gadgets sind.
Boris Treukhov
1
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);    
}

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

Diese Methoden können für jede Aktivität überschrieben werden. Sie können lediglich Werte speichern und wiederherstellen, wenn eine Aktivität erstellt / zerstört wird. Wenn sich die Bildschirmausrichtung ändert, wird die Aktivität zerstört und im Hintergrund neu erstellt. Daher können Sie diese Methoden verwenden während der Änderung Zustände vorübergehend speichern / wiederherstellen.

Sie sollten sich die beiden folgenden Methoden genauer ansehen und prüfen, ob sie zu Ihrer Lösung passen.

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

Chiwai Chan
quelle
1

Die beste Lösung, die ich gefunden habe, um dies zu tun, ohne die vorherige ActivityReferenz configChangeszu verlieren und ohne das .. zu setzen, ist die Verwendung eines MutableContextWrapper .

Ich habe dies hier implementiert: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java

Simon
quelle
Funktioniert dies zuverlässig ohne Nebenwirkungen? Ich habe nicht viele Informationen zu dieser Methode gefunden.
craigrs84
1

Dies ist das einzige, was für mich funktioniert hat (ich habe sogar den Status "Instanz speichern" verwendet, onCreateViewaber er war nicht so zuverlässig).

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

Ich habe einen Singleton-Halter für den Status von WebView erstellt. Der Status bleibt erhalten, solange der Prozess der Anwendung vorhanden ist.

EDIT: Das loadDataWithBaseURLwar nicht nötig, es hat genauso gut mit just funktioniert

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

Obwohl ich gelesen habe, funktioniert dies nicht unbedingt gut mit Cookies.

EpicPandaForce
quelle
Die Verwendung von Singleton ist problematisch, da davon ausgegangen wird, dass Sie nur eine Instanz verwenden müssen.
Android-Entwickler
@androiddeveloper ah. Nun, wenn das in Ihrem Fall nicht stimmt, dann ist das in der Tat ein Problem. Ich hatte nur eine WebView-Instanz, daher kam diese Frage nicht einmal für mich auf.
EpicPandaForce
1

Versuche dies

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

Diese Seite löst mein Problem, aber ich muss die erste geringfügig ändern:

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

Dieser Teil hat für mich ein kleines Problem. Bei der zweiten Ausrichtung wird die Anwendung mit dem Nullzeiger beendet

Damit hat es bei mir funktioniert:

    @Override
protected void onSaveInstanceState(Bundle outState ){
    ((WebView) findViewById(R.id.webview)).saveState(outState);
}
Gyanu
quelle
scheint genau das gleiche zu sein. Warum sollte der zweite funktionieren, während der vorherige nicht funktioniert?
Android-Entwickler
0

Sie sollten dies versuchen:

  1. Erstellen Sie einen Dienst. Erstellen Sie innerhalb dieses Dienstes Ihre WebView.
  2. Starten Sie den Dienst von Ihrer Aktivität aus und binden Sie ihn daran.
  3. In dem onServiceConnectedVerfahren, das WebView zu erhalten und die ruft setContentViewMethode , um Ihre WebView zu machen.

Ich habe es getestet und es funktioniert, aber nicht mit anderen WebViews wie XWalkView oder GeckoView.

Ramdane Oualitsen
quelle
Hallo! Könnten Sie es mehr erklären? Vielen Dank
Jaco
1
Holen Sie sich Ihre Webview-Instanz aus Ihrer Aktivität und versuchen Sie, die Aktualisierung auf einen Dienst zu übertragen, der im Hintergrund ausgeführt wird. Wenn Sie diese Aktivität das nächste Mal öffnen, versuchen Sie zuerst, die gespeicherte Webansicht abzurufen und zu rendern.
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
quelle
Könnten Sie Ihrer Antwort einige Erklärungszeilen hinzufügen?
Yacc
-1

Ich mag diese Lösung http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

Demnach verwenden wir dieselbe Instanz von WebView wieder. Es ermöglicht das Speichern des Navigationsverlaufs und des Bildlaufs bei Konfigurationsänderungen.

Taras Shevchuk
quelle
Der obige Link führt zu einer Seite, die ohne Installation eines Sicherheits-Plugins nicht angezeigt werden kann. vermeiden.
Allan Bazinet