Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing Android WebView from reloading page on rotate in Xamarin environment

I realize there are lots of questions relating to this but I have tried all solutions for native development and can not get them to work under Xamarin.

I have a webview which is loaded with a URL that contains a graphical UI for drawing. When the device is rotated the webview reloads the page and the users work is lost.

The following blog post gives the best solution to this and explains that the widely documented solution is not sufficicient for the following reason:

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

The main problem with this implementation is that, whenever you rotate the screen, the >WebView is created again because the activity is destroyed and its saveState method doesn’t >save the full state, but only a part of it like the URL of the page that was loaded and the >browsing history. So it happens that for example the zoom and the scroll position are not >preserved after the screen orientation change and sometimes the page is reloaded from the web.

So I have implemented their solution, porting it from Java to Xamarin C#. It looks promising but whenever my activity reloads and InitUi is called, the web_view class variable is always null whereas the example relies on this class variable holding its value between device rotations.

Anyone any idea why web_view loses its value?

Here's my code which is exactly like the article but ported to Xamarin C#.

public class EbookViewerActivity : ActionBarActivity
{
    protected WebView web_view;
    protected FrameLayout webViewPlaceholder;

    Button loadButton;
    Button downloadButton;
    EditText testUrlText;
    private string viewerPath;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        #region Set up activity and action bar

        //Create the activity screen and initialise the action bar
        base.OnCreate(savedInstanceState);
        RequestWindowFeature(WindowFeatures.NoTitle);
        SetContentView(Resource.Layout.Viewer);
        InitializeActionBar();

        //Set action bar button delegates
        ActionBar
            .AddLeftAction(new DelegateAction(Finish, Resource.Drawable.CloseIcon))
            .SetTitle("Ebook Annotator");

        //Set action bar logo
        ActionBar.SetHomeLogo(Resource.Drawable.AcmeTrainingLogo);
        #endregion

        InitUi();
    }

    private void InitUi()
    {
        Logger logger = Logger.Instance;
        // Retrieve UI elements
        webViewPlaceholder = FindViewById<FrameLayout>(Resource.Id.webViewPlaceholder);
        // Initialize the WebView if necessary
        if (web_view == null)
        {
            web_view = new WebView(this);
            web_view.Id = Resource.Id.ebookDynamicWebView;

            //web_view = FindViewById<WebView>(Resource.Id.ebookWebview);
            web_view.Settings.JavaScriptEnabled = true;
            web_view.AddJavascriptInterface(new AnnotationApiProxy(this), "AnnotationApi");
            string ebookId = Intent.GetStringExtra("ebookId");
            string userEmail = Intent.GetStringExtra("userEmail");
            Ebook ebook = EbookManager.GetEbook(int.Parse(ebookId));

            GlobalVariableHolder.Instance.EbookToOpen = int.Parse(ebookId);
            viewerPath = "file:///android_asset/Annotator/annotator.html";

            web_view.Settings.AllowFileAccess = true;
            logger.WriteToLog("Loading test harness with ebook id: " + ebookId, LogEntryLevel.Message);
            web_view.SetWebChromeClient(new EbookWebViewClient() { });
           // web_view.SetWebViewClient(new WebViewClient());
            AnnotationDownloader annotationDownloader = new AnnotationDownloader();
           // annotationDownloader.XmlDownloaded += (sender, args) => RunOnUiThread(() =>
         //   {
                web_view.LoadUrl(viewerPath);
           // });
            annotationDownloader.GetLatestEWorkBookXml(ebook.ID, userEmail);
        }

        // Attach the WebView to its placeholder
        webViewPlaceholder.AddView(web_view);
    }

    protected override void OnSaveInstanceState(Bundle outState)
    {
        base.OnSaveInstanceState(outState);
        // Save the state of the WebView
        web_view.SaveState(outState);
    }

    protected override void OnRestoreInstanceState(Bundle savedInstanceState)
    {
        base.OnRestoreInstanceState(savedInstanceState);
        // Restore the state of the WebView
        web_view.RestoreState(savedInstanceState);
    }

    public override void OnConfigurationChanged(Configuration newConfig)
    {
        if (web_view != null)
        {
            // Remove the WebView from the old placeholder
            webViewPlaceholder.RemoveView(web_view);
        }
        base.OnConfigurationChanged(newConfig);
        // Load the layout resource for the new configuration
        SetContentView(Resource.Layout.Viewer);
        // Reinitialize the UI
        InitUi();
    }
}
like image 714
Dan Cook Avatar asked Oct 02 '22 15:10

Dan Cook


1 Answers

Do not change AndroidManifest.xml and use custom attributes.

[Activity(ConfigurationChanges=ConfigChanges.Orientation | ConfigChanges.ScreenSize)] 
    public partial class MyActivity : Activity { ...

This solution has worked with me.

like image 156
Ive Avatar answered Oct 07 '22 04:10

Ive