On Aug 9, 2012, at 10:50 AM, subsembly <a.se...@subsembly.com> wrote:
> I am trying to understand what exactly happens when I am using an 
> Android.Widget.ArrayAdapter<string> for my list views and spinners. 
> Considering the following sample code from an Activity:
> 
> string[] vs = new string[] { "one", "two", "three" }
> ArrayAdapter<string> aa = new ArrayAdapter<string>(this, 
> Android.Resource.Layout.SimpleSpinnerItem, vs);
> Spinner s = (Spinner)this.FindViewById(Resource.Id.myspinner);
> s.Adapter = aa;
> 
> I know that on the Java side, the ArrayAdapter needs a Java list with Java 
> objects. How is Mono for Android converting my C# string to the Java objects 
> that Java needs?

Lots of JNI glue. ;-)

The array is "deep copied" into Java.

The string[] is marshaled into a Java-side array via JNIEnv.NewObjectArray(), 
which in this case will allocate a Java-side java.lang.String[], then copy each 
element of the C# string[] into the Java String[] via JNIEnv.NewString(). No 
grefs are required.

If you were instead dealing with a builtin type such as `int`, the values would 
instead be converted into a java.lang.Integer[], and the values are (again) 
"deep copied." No grefs are required.

When using a Java.Lang.Object subclass, a new Java-side array will be created, 
and each element of the Java-side array will reference the Android Callable 
Wrapper for the C# instance. Each instance will have a gref, but they'd have a 
gref _anyway_; the underlying Java array will not have a gref.

When using any other managed type, a new Java-side java.lang.Object[] array 
will be created, with each element referring to an internal 
mono.android.JavaObject instance which will reference the managed instance. 
Each JavaObject instance will also take out a gref.

> Later in my code when I use
> 
> Java.Lang.Object o = s.SelectedItem;
> 
> How does the returned Java object relate to my original string?

`o` will be a Java.Lang.String instance, which will contain a copy of your 
original string value. This will also cause a gref to be allocated (for 
referential equality); if grefs are an issue, you'll want to dispose of it ASAP.

> And how do I get back to the original string?

The original string instance? You don't. (Thus `object.ReferenceEquals()` is 
out.)

The original string value? `o.ToString()`. You can thus do:

        string item;
        using (var o = s.SelectedItem)
                item = o.ToString();

> Finally: Is there a better (faster, less memory using) way than using an 
> ArrayAdapter<string> at all?

The tradeoff is in performance. For strings, ArrayAdapter<string> should be 
good -- the entire collection is stored in Java, making Java-side object lookup 
fast. There's some overhead in duplicated strings, but there's no way to avoid 
this: as soon as Java code calls ArrayAdapter<String>.getItem(), it'll get a 
Java-side copy of the string anyway; there's no way to avoid that copy.

If you were dealing with some other type, specifically a managed type, you'd 
want to consider forgoing ArrayAdapter<T> altogether and using BaseAdapter<T> 
instead. This will cause item lookup to be _slower_ (due to the transition to 
managed code), but gref counts will also be lower and there will be fewer 
instances allocated.

 - Jon

_______________________________________________
Monodroid mailing list
Monodroid@lists.ximian.com

UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid

Reply via email to