On Aug 9, 2012, at 10:50 AM, subsembly <[email protected]> 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
[email protected]
UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid