Android WebView handling orientation changes

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

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

-------------Problems Reply------------

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

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

http://developer.android.com/intl/de/reference/android/app/Activity.html#ConfigurationChanges

This blog is very usefull in the matter: http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/. It works even for JavaScript variables etc.

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

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

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

android:screenOrientation="portrait"

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

@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

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

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

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

}

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/master/WebWrapper/src/com/example/webwrapper/BrowserActivity.java

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.

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

}

Adapted from here

Hope this helps :)

I know this is theoretically horrible, but 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.

Category:android Views:3 Time:2009-06-16

Related post

  • Android: Wakelock & handling orientation change 2010-01-13

    I'm using Wakelock in my application to prevent the phone from sleeping when the app is visible. The problem comes when there is an orientation change and the system destroys and re-creates the app in landscape mode. If the wakelock timer has expired

  • android WebView: Handle arrow keys in javacript 2012-04-16

    I have a simple WebView application which I want to control with the keyboard. Is it possible to catch arrow keys in javascript? I have tried the following code without any luck: function handleArrowKeys(evt) { console.info('key'); } document.onkeyup

  • Android: Handling orientation changes myself - RelativeLayout is getting messed up 2011-01-12

    In an Android app, I've got an activity that is somewhat complex and may have threads running at certain times which, when finished, will update the UI. As such, having the Activity destroy and create again (due to orientation change) in the middle o

  • Handling orientation changes android 2011-11-24

    I have a Table containing a number of images per row. The number of images per row is decided on the fly based on the image width and screen width. When I use the phone normally, images are spaced on the phone screen. When the phone orientation chang

  • Android webview retain form data when orientation changes 2012-01-04

    How to retain the form data in the webview after the change the orientation ? I have used onSaveInstanceState() and I have restored the previous state using restoreState(savedInstanceState). This successfully restores the previous state before the ch

  • Android Webview - How to retain text data when orientation changes 2012-01-22

    I want to retain the text data in the webview (i.e the data entered in the text box of the form in the url loaded) across the orientation changes. I used, onSaveInstanceState() *restoreState(savedInstanceState) it restores previous state but not the

  • android restoring webview during orientation change in tabhost tabs 2012-03-08

    In my application i have a tabhost with three tabs. All the three tabs has a webview and i load different URLS. I want to add support for orientation change so that the web pages will not be reloaded each time the configuration is changed. So i added

  • Android Webview content should not be lost on orientation change, but GUI should be updated properly 2012-03-19

    I have been trying to keep the loaded page and javascript values of a WebView on orientation change and pausing the activity. First I tried overriding configChanges, but that resulted in my GUI not being updated properly (i have a slidingdrawer that

  • Android GridView Reversing After Handling Orientation Change 2010-06-19

    EDIT: This problem may be related to http://stackoverflow.com/questions/3121153/baseadapter-causing-listview-to-go-out-of-order-when-scrolled My main application screen uses a GridView to display a grid of icons. Each icon has an image, name, and Int

  • How to handle facebook like with confirm in android webview 2011-09-20

    I am trying to implement facebook like functionality using android webview. It is working fine without "confirm" dialog. But its not working when like needs confirmation. Here is the code snippet i am using. private void setUpWebView() { likeWebView.

  • Android webview crashing? 2011-09-03

    I'm trying to make an app for a website, basically just loads the website. I know how to make it and everything, and I've set up webviews, but I'm not sure what I'm doing wrong. So basically my main class loads a menu, it has buttons for like home, f

  • My Android Webview App Closes when I tried to put AdMob Ads 2013-06-14

    Hi My app is forcefully closing and I dont know what is the problem in my code. can any one help.. When I run the apk file it says unfortunately app has been stopped PACKAGE CODE package net.learnscripture.webviewapp; import com.google.ads.AdRequest;

  • Android WebView crashes when clicking on a link 2009-10-13

    I have some WebView widgets inside my Activity. I use loadData() to set the content, and this html contains a link. Some of my WebViews work okay, when I click the link, the web browser is started in a new window, but some make my app crash when I cl

  • Where are JavaScript exceptions displayed when using Android WebView? 2010-02-09

    I have this simple HTML that I load into an Android WebView (SDK version 1.5)- <html> <body onload="nomethod()"> <h1>Hello World</h1> </body> </html> Function nomethod() doesn't exist but the LogCat doesn't display

  • How to refresh an Android RelativeLayout when orientation changes without restarting the Activity? 2010-06-07

    I have an Android Activity with a RelativeLayout and I have implemented the following method to prevent the activity from being recreated on change of Orientation: @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfig

  • Problems when handling orientation changes 2010-06-07

    I need to handle orientation changes in my Android application. For this purpose I decided to use OrientationEventListener convenience class. But his callback method is given somewhat strange behavior. My application starts in the portrait mode and t

  • Android Webview Anchor Link (Jump link) not working 2010-06-14

    I have a WebView in my Android App that is loading an HTML string using the loadDataWithBaseURL() method. The problem is that local anchor links (<a href="#link">...) are not working correctly. When the link is clicked, it becomes highlighted,

  • Weird problem on android webview with canvas 2010-07-10

    I am draw some canvas charts on the android webview, and use javascript to change chart just by hiding and showing, and also change the title by reset its innerHTML. The title is just a normal html tag "<div id='title'></div>", The proble

  • How to avoid scaling of android webview 2010-08-19

    hi Is there any way to prevent android webview to scale the rendered web page . I need to load an url which has links to other pages .When user clicks these links the rendered page is not aligned properly(i mean it cramps all the stuff within the scr

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.138 (s). 11 q(s)