Screen Rotation with Threading using Mono Android?

2019-06-09 23:05发布

问题:

In CommonsWare eBook Android v3.6 pg 270, he discusses handling threads with rotation. He offers a solution where you create an inner static class to hold your state, call detach in the workflow and then attach again during screen rotation.

The problem is that each rotation will destroy the Activity and recreate it in Android, thus when you come back your thread may reference the destroyed activity giving you an exception for accessing an object set for collection.

I tried this in Mono Android and was unable to get it to work, I got an exception every single time. My question, hopefully Jonathan Pryer reads this is, how can I make this work in Mono Android? I have asked this twice on the forums with no results. So I am taking it to StackOverflow. I wanted to post the actualy code but I didn't want to violate CommonsWare licensing. So please take a look at the example in the book.

回答1:

What was the exception? What's the adb logcat output?

The C# equivalent is the-same-but-different from the Java source. For example, here's the "rotation-aware" version of the default Mono for Android sample project:

[Activity (Label = "Scratch.PreserveCount", MainLauncher = true)]
public class Activity1 : Activity
{
    CountInfo Info;

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        // Set our view from the "main" layout resource
        SetContentView (Resource.Layout.Main);

        // Get our button from the layout resource,
        // and attach an event to it
        Button button = FindViewById<Button> (Resource.Id.myButton);

        button.Click += delegate {
            SetButtonCount (button, Info.Count++);
        };

        Info = (CountInfo) LastNonConfigurationInstance;
        if (Info == null) {
            Info = new CountInfo {
                Count = 1,
            };
        } else {
            SetButtonCount (button, Info.Count);
        }
    }

    void SetButtonCount (Button button, int count)
    {
        button.Text = string.Format ("{0} clicks!", Info.Count);
    }

    public override Java.Lang.Object OnRetainNonConfigurationInstance ()
    {
        return Info;
    }

    class CountInfo : Java.Lang.Object {
        public int Count;
    }
}

It's the same basic approach as the Java sample: the Activity.OnRetainNonConfigurationInstance() method is invoked by Android before the Activity is disposed, so we return our "state" from that method. The Activity.LastNonConfigurationInstance property will return null the first time it's invoked, otherwise it will return the last value returned from OnRetainNonConfigurationInstance(). The only missing piece of the puzzle is that the "state" object (CountInfo here) must inherit from Java.Lang.Object as we're passing the instance to Java.