Yura Sokolov Yura Sokolov - 3 months ago 13
C# Question

Prevent activity from reload after rotation in xamarin, monodroid

Ok... So my problem is to prevent from activity to reload after orientation is changed.
Basically, what I did is this:

[Activity(Label = "migs", ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation)]


This is worked fine, until I changed "Target API" to 14. If I'm changing it back to 12, then everything is working, but on 14, activity is being restarted (OnCreate method is fires after rotation).
So... You'll ask why do I need "Target API" 14? - Easy! Because in my app, I'm playing video, and for that I need "true full screen". All API's below 14 adding "Settings" (three dots) button. In case of HTC, it's big and ugly button, that I was unable to get rid of.

If you know how to do one of the two (Get rid of the "settings" button in API 12, or prevent activity from reload after orientation changed in API 14), I'll be very thank full for your help.

Answer

Ok... At last I solved it! :) Saving activity state instead of preventing activity from reload, from first sight can seem to be a little tricky, but in fact is really easy and it's the best solution for situations like this. In my case, I had a ListView, that populates from the internet with items, that stored in custom list adapter. If device orientation was changed, the activity was reloaded, so does the ListView, and I was loosing all the data. All I needed to do is to override the OnRetainNonConfigurationInstance method. Here's a quick sample of how to do it.
First of all, we need a class, that can handle all of our stuff.

Here is a wrapper for all the things we need to save:

public class MainListAdapterWrapper : Java.Lang.Object
{
    public Android.Widget.IListAdapter Adapter { get; set; }
    public int Position { get; set; }
    public List<YourObject> Items { get; set; }
}

In our activity, we need to hold variables, to store all the data:

ListView _listView; //Our ListView
List<YourObject> _yourObjectList; //Our items collection
MainListAdapterWrapper _listBackup; //The instance of the saving state wrapper
MainListAdapter _mListAdapter; //Adapter itself

Then, we overriding the OnRetainNonConfigurationInstance method in the activity:

public override Java.Lang.Object OnRetainNonConfigurationInstance()
{
    base.OnRetainNonConfigurationInstance();
    var adapterWrapper = new MainListAdapterWrapper();
    adapterWrapper.Position = this._mListAdapter.CurrentPosition; //I'll explain later from where this came from
    adapterWrapper.Adapter = this._listView.Adapter;
    adapterWrapper.Items = this._yourObjectList;
    return adapterWrapper;
}

And the final stage is to load saved state in OnCreate method:

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.list);

    this._listView = FindViewById<ListView>(Resource.Id.listView);

    if (LastNonConfigurationInstance != null)
    {
        this._listBackup = LastNonConfigurationInstance as MainListAdapterWrapper;
        this._yourObjectList = this._listBackup.Items;
        this._mListAdapter = this._listBackup.Adapter as MainListAdapter;
        this._listView.Adapter = this._mListAdapter;

        //Scrolling to the last position
        if(this._listBackup.Position > 0)
            this._listView.SetSelection(this._listBackup.Position);
    }
    else
    {
        this._listBackup = new MainListAdapterWrapper();
        //Here is the regular loading routine
    }

}

And about the this._mListAdapter.CurrentPosition... In my MainListAdapter, I added this property:

public int CurrentPosition { get; set; }

And the, in the `GetView' method, I did that:

this.CurrentPosition = position - 2;

P.S.

You don't have to implement exactly as I showed here. In this code, I'm holding a lot of variables, and making all the routine inside the OnCreate method - that is wrong. I did that, just to show how it can be implemented.

Comments