Skip to content
This repository was archived by the owner on May 29, 2024. It is now read-only.

Commit 97bf49b

Browse files
committed
[Mono.Android] Prefer BaseAdapter over ArrayAdapter.
BaseAdapter/BaseAdapter<T> should be preferred over ArrayAdapter/ArrayAdapter<T> when the element type is NOT a Java.Lang.Object subclass. Non-Java.Lang.Object types will be implicitly wrapped in a Java.Lang.Object subclass, requiring a GREF for each element stored within the ArrayAdapter, and many Android targets have a limited GREF count. Using BaseAdapter allows for using a GREF only for each _displayed_ item instead of for each item. From: http://lists.ximian.com/pipermail/monodroid/2012-August/011730.html On Aug 9, 2012, at 10:50 AM, subsembly <a.selle at 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
1 parent d5a8ad4 commit 97bf49b

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

docs/Mono.Android/en/Android.Widget/ArrayAdapter.xml

+12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@
2525
<summary>A concrete BaseAdapter that is backed by an array of arbitrary
2626
objects.</summary>
2727
<remarks>
28+
<para>
29+
In Xamarin.Android, inheriting from
30+
<see cref="T:Android.Widget.BaseAdapter" /> is preferred
31+
over using <c>ArrayAdapter</c> <i>unless</i> the adapter will be
32+
storing <see cref="T:Java.Lang.Object"/> instances. The reason for
33+
this is GREF counts: many Android targets can only maintain a limited
34+
number of GREFs, and with <c>ArrayAdapter</c> there will be one GREF
35+
per <c>ArrayAdapter</c> item. By using <c>BaseAdapter</c>, this can be
36+
reduced to one GREF per displayed item, which for large lists can be
37+
significantly smaller.
38+
(<format type="text/html"><a href="http://lists.ximian.com/pipermail/monodroid/2012-August/011730.html">Longer rationale</a></format>).
39+
</para>
2840
<para tool="javadoc-to-mdoc">A concrete BaseAdapter that is backed by an array of arbitrary
2941
objects. By default this class expects that the provided resource id references
3042
a single TextView. If you want to use a more complex layout, use the constructors that

docs/Mono.Android/en/Android.Widget/ArrayAdapter`1.xml

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222
<summary>A concrete BaseAdapter that is backed by an array of arbitrary
2323
objects.</summary>
2424
<remarks>
25+
<para>
26+
In Xamarin.Android, inheriting from
27+
<see cref="T:Android.Widget.BaseAdapter{T}" /> is preferred
28+
over using <c>ArrayAdapter</c> <i>unless</i> the adapter will be
29+
storing <see cref="T:Java.Lang.Object"/> instances. The reason for
30+
this is GREF counts: many Android targets can only maintain a limited
31+
number of GREFs, and with <c>ArrayAdapter</c> there will be one GREF
32+
per <c>ArrayAdapter</c> item. By using <c>BaseAdapter</c>, this can be
33+
reduced to one GREF per displayed item, which for large lists can be
34+
significantly smaller.
35+
(<format type="text/html"><a href="http://lists.ximian.com/pipermail/monodroid/2012-August/011730.html">Longer rationale</a></format>).
36+
</para>
2537
<para tool="javadoc-to-mdoc">A concrete BaseAdapter that is backed by an array of arbitrary
2638
objects. By default this class expects that the provided resource id references
2739
a single TextView. If you want to use a more complex layout, use the constructors that

0 commit comments

Comments
 (0)