148

The issue is the performance following rotation. The WebView has to reload the page, which can be a bit tedious.

What's the best way of handling an orientation change without reloading the page from source each time?

Jonathan Soifer
  • 2,387
  • 5
  • 23
  • 47
glennanthonyb
  • 1,815
  • 2
  • 14
  • 10

20 Answers20

91

If you do not want the WebView to reload on orientation changes simply override onConfigurationChanged in your Activity class:

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

And set the android:configChanges attribute in the manifest:

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

for more info see:
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

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

Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
Totach
  • 1,763
  • 1
  • 15
  • 20
  • 4
    I tested but found do not work, set configChanges attribute like below will work. android:configChanges="keyboardHidden|orientation" – virsir Feb 27 '10 at 16:05
  • 21
    doing that is in fact discouraged, as has been mentioned many times before – Matthias Nov 26 '10 at 17:00
  • 3
    Matthias: This is not really true - see Javadoc for WebView. – krtek Mar 17 '11 at 16:00
  • Two things to note about this solution: 1) If you have an abstract Activity with a WebView, the `configChanges` attribute gets added to the subclass Activity 2) If your app depends on multiple projects, the `configChanges` attribute gets added to the manifest of the one at the top of the dependency tree (which may not be the project containing the Activity class). – Amanda S Jul 19 '11 at 18:04
  • +1 for android:configChanges="orientation|screenSize". I had android:configChanges="keyboardHidden|orientation" but was missing the screenSize flag. It now works like a charm! – Luis Mar 31 '13 at 04:38
  • orientation|screenSize with Android 3.2 (API level 13) – bungdito Jun 07 '13 at 05:36
  • Hmmm... I get "error: Error: String types not allowed (at 'configChanges' with value 'orientation|screenSize')." – alexander7567 Nov 04 '13 at 19:59
  • Works perfect for me when I changed it to android:configChanges="orientation|screenLayout" – alexander7567 Nov 04 '13 at 21:24
  • Android is a platform where things that don't work are encouraged and things thad DO work are discouraged. – Josh Aug 17 '15 at 15:56
  • 6
    Such `onConfigurationChanged` method override is useless. – Miha_x64 May 22 '17 at 16:05
  • Working on android 4.1 – Alejandro del Río Nov 24 '17 at 03:11
  • Works on Android Oreo. – Sabri Meviş Jun 08 '18 at 13:41
  • Do you know how to make when orientation changes make full screen for when it is in landscape make full video of youtube while playing ? – Abedin.Zhuniqi Feb 04 '19 at 13:59
70

Edit: This method no longer works as stated in the docs


Original answer:

This can be handled by overrwriting onSaveInstanceState(Bundle outState) in your activity and calling saveState from the webview:

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

Then recover this in your onCreate after the webview has been re-inflated of course:

public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.blah);
   if (savedInstanceState != null)
      ((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
Michał Klimczak
  • 11,170
  • 7
  • 55
  • 92
KWright
  • 757
  • 5
  • 2
  • 26
    This doesn't work on orientation change — blank screen is shown. saveState\restoreState methods are called but it doesn't help. – Oleksii Malovanyi Nov 09 '11 at 12:55
  • 1
    Here is onCreate code snippet: setContentView(R.layout.webview); mWebView = (WebView) findViewById(R.id.webview); if (savedInstanceState == null) { mWebView.getSettings().setJavaScriptEnabled(true); mWebView.setWebViewClient(new SimpleWebViewClient()); mWebView.loadUrl(Consts.URL_AUTHORIZATION_OAUTH); } else { mWebView.restoreState(savedInstanceState); } – Oleksii Malovanyi Nov 09 '11 at 12:56
  • 12
    From the documentation of saveState: _Please note that this method no longer stores the display data for this WebView. The previous behavior could potentially leak files..._ – brillenheini Jun 25 '13 at 09:36
  • 5
    "Please note that this method no longer stores the display data for this WebView" - http://developer.android.com/reference/android/webkit/WebView.html – Steven Mark Ford Aug 21 '14 at 10:54
  • Does anyone have any suggestion on what to do now that "this method no longer stores the display data for this WebView" in order to prevent a WebView form reloading? – Lucas P. Oct 07 '19 at 13:18
24

The best answer to this is following Android documentation found here Basically this will prevent Webview from reloading:

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

Edit(1/4/2020): You don't need this optional code, the manifest attribute is all you need, leaving optional code here to keep answer complete.

Optionally, you can fix anomalies (if any) by overriding onConfigurationChanged in the activity:

@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();
    }
}
Booger
  • 18,137
  • 6
  • 51
  • 64
Tinashe
  • 2,987
  • 3
  • 20
  • 23
  • 6
    You don't need the onConfigurationChanged() method I am pretty sure, just the additional attribute in the Manifest. My guess is that native support for this was provided by the WebView, and this is why this answer is now the best one (because this didn't work when the question was originally asked) – Booger Dec 17 '15 at 16:14
  • 1
    I approve @Booger you dont need to override the onConfigurationChanged() method.All you need is add android:configChanges="orientation|screenSize" in manifest.xml file. – ozanurkan Apr 16 '19 at 12:44
  • @Booger in answer also saying, optional that code, not mandatory. – Mohd Qasim Dec 28 '20 at 18:11
5

I've tried using onRetainNonConfigurationInstance (returning the WebView), then getting it back with getLastNonConfigurationInstance during onCreate and re-assigning it.

Doesn't seem to work just yet. I can't help but think I'm really close though! So far, I just get a blank/white-background WebView instead. Posting here in the hopes that someone can help push this one past the finish line.

Maybe I shouldn't be passing the WebView. Perhaps an object from within the WebView?

The other method I tried - not my favorite - is to set this in the activity:

 android:configChanges="keyboardHidden|orientation"

... and then do pretty much nothing here:

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

THAT works, but it might not be considered a best practice.

Meanwhile, I also have a single ImageView that I want to automagically update depending on the rotation. This turns out to be very easy. Under my res folder, I have drawable-land and drawable-port to hold landscape/portrait variations, then I use R.drawable.myimagename for the ImageView's source and Android "does the right thing" - yay!

... except when you watch for config changes, then it doesn't. :(

So I'm at odds. Use onRetainNonConfigurationInstance and the ImageView rotation works, but WebView persistence doesn't ... or use onConfigurationChanged and the WebView stays stable, but the ImageView doesn't update. What to do?

One last note: In my case, forcing orientation isn't an acceptable compromise. We really do want to gracefully support rotation. Kinda like how the Android Browser app does! ;)

Joe D'Andrea
  • 5,101
  • 6
  • 46
  • 67
  • 8
    You shouldn't return any Views from onRetainNonConfigurationInstance. The views are attached to the Activity Context so if you save the view you carry over all that baggage every time there is an orientation change. The view is "leaked". (See last paragraph here: http://developer.android.com/resources/articles/faster-screen-orientation-change.html) The best practice for onRetainNonConfigurationInstance is to save the data that the view needs, not the view itself. – Declan Shanaghy Jan 22 '10 at 01:07
4

Best way to handle orientation changes and Preventing WebView reload on Rotate.

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

With that in mind, to prevent onCreate() from being called every time you change orientation, you would have to add android:configChanges="orientation|screenSize" to the AndroidManifest.

or just ..

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

One compromise is to avoid rotation. Add this to fix the activity for Portrait orientation only.

android:screenOrientation="portrait"
Jacques René Mesrine
  • 41,077
  • 24
  • 60
  • 99
3

I appreciate this is a little late, however this is the answer that I used when developing my solution:

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

}
Samuel Liew
  • 68,352
  • 105
  • 140
  • 225
David Passmore
  • 5,941
  • 4
  • 42
  • 68
3

Just write the following code lines in your Manifest file - nothing else. It really works:

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

You can try using onSaveInstanceState() and onRestoreInstanceState() on your Activity to call saveState(...) and restoreState(...) on your WebView instance.

Amanda S
  • 3,178
  • 4
  • 31
  • 45
deltaearl
  • 73
  • 8
2

It is 2015, and many people are looking for a solution that still workds on Jellybean, KK and Lollipop phones. After much struggling I found a way to preserve the webview intact after you change orientation. My strategy is basically to store the webview in a separate static variable in another class. Then, if rotation occurs, I dettach the webview from the activity, wait for the orientation to finish, and reattach the webview back to the activity. For example... first put this on your MANIFEST (keyboardHidden and keyboard are 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>

In a SEPARATE APPLICATION CLASS, put:

     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 the ACTIVITY put:

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

Finally, the simple 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>

There are several things that could be improved in my solution, but I already spent to much time, for example: a shorter way to validate if the Activity has been launched for the very first time instead of using SharedPreferences storage. This approach preserves you webview intact (afaik),its textboxes, labels, UI, javascript variables, and navigation states that are not reflected by the url.

Josh
  • 5,781
  • 1
  • 39
  • 67
  • 1
    Why even bother detaching and reattaching the WebView when it never gets destroyed in the first place since you manually handle configuration changes? – Fred Nov 06 '15 at 15:46
  • @Fred Because I want to keep the exact state of the Webview and its contents intact, including cookies, and the state of buttons and checkboxes implemented with HTML5 or JS inside webpage loaded by the webview. The only adjustment I do is resizing. – Josh Nov 06 '15 at 21:42
  • Fred meant you don't need to detach/reattach the webview via a static class as you declared configChanges in the manifest. This way, your views and activity don't get destroyed during rotation in any case. – Eugene Kartoyev Oct 18 '19 at 00:41
2

Update: current strategy is to move WebView instance to Application class instead of retained fragment when it's detached and reattach on resume as Josh does. To prevent Application from closing, you should use foreground service, if you want to retain state when user switches between applications.

If you are using fragments, you can use retain instance of the WebView. The web view will be retained as instance member of the class. You should however attach web view in OnCreateView and detach before OnDestroyView to prevent it from destruction with the parent container.

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

P.S. Credits go to kcoppock answer

As for 'SaveState()' it no longer works according to official documentation:

Please note that this method no longer stores the display data for this WebView. The previous behavior could potentially leak files if restoreState(Bundle) was never called.

Community
  • 1
  • 1
Boris Treukhov
  • 16,478
  • 9
  • 66
  • 86
  • Note that while `setRetainInstance` does retain the Fragment the view (and hence the WebView) still gets destroyed. – Fred Nov 06 '15 at 15:48
  • 1
    @Fred Can you provide a source for that statement? I have tested this in a small app which has a fragment with setRetainInstance(true) that displays a youtube page and if I change the orientation, the view seems to be retained as the video is not interrupted. Doesn't seem like the webview is getting destroyed. – lv99Zubat Feb 03 '16 at 21:36
  • @Rai It's was just a misreading, I have edited a bit the answer since then(it still needs some wording fixes). If you are interested in current state of affairs - this method works. However the problem is that android kills application when it's low on memory. I have an important input form where user has to read a message in another application, so I had to use foreground service with notification to prevent process from being killed. Yet android still destroys activity and hence the retained frame. But the instance of Application class is preserved - so I move WebView to Application now. – Boris Treukhov Feb 03 '16 at 22:17
  • 1
    I also use MutableContextWrapper as base of the WebView, I switch contexts to activities on attach and detach. Another big problem that Chromium build in zoom controls save reference to old activity, so no zoom in solution with WebView attached to Application instead of Activity. **TL;DR;** if your form is not that important, and you may live with fact that after app switching your process can be killed and webview not restored go with retained frame solution. P.S. also I think that Google employees are far, far from real life problems with all their widgets-gadgets.. – Boris Treukhov Feb 03 '16 at 22:22
2

The only thing you should do is adding this code to your manifest file:

<activity android:name=".YourActivity"
      android:configChanges="orientation|screenSize"
      android:label="@string/application_name">
Les Paul
  • 219
  • 1
  • 4
  • 15
1
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);    
}

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

These methods can be overridden on any activity, it just basically allows you to save and restore values each time an activity is created/destroyed, when the screen orientation changes the activity gets destroyed and recreated in the background, so therefore you could use these methods to temporary store/restore states during the change.

You should have a deeper look into the two following methods and see whether it fits your solution.

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

nmikhailov
  • 1,293
  • 13
  • 24
Chiwai Chan
  • 4,370
  • 4
  • 27
  • 32
1

The best solution I have found to do this without leaking the previous Activity reference and without setting the configChanges.. is to use a MutableContextWrapper.

I've implemented this here: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java

Simon
  • 9,933
  • 44
  • 46
1

This is the only thing that worked for me (I even used the save instance state in onCreateView but it wasn't as reliable).

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

I made a Singleton holder for the state of the WebView. The state is preserved as long as the process of the application exists.

EDIT: The loadDataWithBaseURL wasn't necessary, it worked just as well with just

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

Although I read this doesn't necessarily work well with cookies.

EpicPandaForce
  • 71,034
  • 25
  • 221
  • 371
  • Using singleton is problematic, as it assumes you have only one instance that you need to use. – android developer Mar 01 '15 at 15:17
  • @androiddeveloper ah. Well, if that's not true in your case, then indeed that is a problem. I only had one WebView instance, so this question didn't even come up for me. – EpicPandaForce Mar 01 '15 at 21:42
1

try this

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
  • 354
  • 1
  • 3
  • 11
0

You should try this:

  1. Create a service, inside that service, create your WebView.
  2. Start the service from your activity and bind to it.
  3. In the onServiceConnected method, get the WebView and call the setContentView method to render your WebView.

I tested it and it works but not with other WebViews like XWalkView or GeckoView.

dakab
  • 4,576
  • 8
  • 38
  • 56
  • Hi! Could you explain it more? Thank you – Jaco Nov 15 '18 at 16:27
  • 1
    Well, get your webview instance form you Activity and try to put its refrence to a service that is running in background. The next time you open that activity, try to get the saved webview first and render it. – Ramdane Oualitsen Nov 18 '18 at 23:13
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
  • 123
  • 1
  • 1
  • 9
0

This page solve my problem but I have to make slight change in initial one:

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

This portion has a slight problem for me this. On the second orientation change the application terminated with null pointer

using this it worked for me:

    @Override
protected void onSaveInstanceState(Bundle outState ){
    ((WebView) findViewById(R.id.webview)).saveState(outState);
}
Flexo
  • 82,006
  • 22
  • 174
  • 256
gyanu
  • 915
  • 1
  • 8
  • 19
-1

I like this solution http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

According to it we reuse the same instance of WebView. It allows to save navigation history and scroll position on configuration change.

Taras Shevchuk
  • 311
  • 2
  • 12