On May 16, 2012, at 3:01 AM, Igor Russkih wrote:
> It seems SimpleAdapter is broken (found this in 4.2 alpha), 4.2.1 release 
> also have this issue:

This is a "regression" that won't be fixed; see:

        http://lists.ximian.com/pipermail/monodroid/2012-May/010250.html
        https://bugzilla.xamarin.com/show_bug.cgi?id=2147

The problem is one of preserving object identity between VMs. For example, 
consider the following code:

        var list = new JavaList<object>();

JavaList is a java.util.ArrayList, in which every value is referenced in the 
Java VM.

        var value = new XElement (/* ... */);
        list.Add (value);

So we've just added an XElement instance to a Java-side list. Okay... So what 
should the following do:

        var v = list [0];
        object.ReferenceEquals (v, value);

Should object.ReferenceEquals() be true or false?

Prior to 4.2.1, it would be false, and `v` would refer to an 
Android.Runtime.JavaObject instance (which isn't even public!), leading to all 
manner of Reflection-hackery to get back the original value. This is pretty bad.

The "good" news was that if it was a Dictionary instead of an XElement, it 
would be "deep marshaled" into Java: the Dictionary contents would be copied 
into a java.util.HashMap. The fundamental problem remained, though: `list[0]` 
would not return `value`, it would (at best) give a separate copy. Worse (for 
varying values of "worse"), there'd be a _ton_ of global references held during 
that marshaling operation, none of which would get collected until the entire 
object graph was collectable by both VMs.

In short, it worked, but it was a mess. It led to "bizarre" behavior, and 
increased gref use.

(Truly, I should have fixed that for 4.0, but I wasn't able to carve out the 
time...)

The fix? Use types which won't be implicitly wrapped into an 
Android.Runtime.JavaObject, i.e. the (public) Android.Runtime collection types.

>             var settings_data = new List<IDictionary<string, object>>();

        var settings_data = new JavaList<IDictionary<string, object>>();
> 
>             sa = Resources.ObtainTypedArray(Resource.Array.settings_text);
>             sa_icons = 
> Resources.ObtainTypedArray(Resource.Array.settings_icons);
> 
>             for (int i = 0; i < sa.Length(); i++)
>             {
>                 var item = new Dictionary<string, object>();

                var item = new JavaDictionary<string, object>();

>                 item["text"] = sa.GetString(i);
>                 item["icon"] = sa_icons.GetResourceId(i, 0);
>                 settings_data.Add(item);
>             }
> 
>             this.ListAdapter = new SimpleAdapter(this, settings_data,
>                 Resource.Layout.list_item_icon_text, new String[] { "text", 
> "icon" },
>                 new int[] { Resource.Id.text, Resource.Id.icon });

Two changes to two lines should fix your exception.

The above still keeps grefs around for longer than absolutely necessary; you 
can use some `using`s to further decrease the lifetime of the collections, as 
outlined at:

        http://lists.ximian.com/pipermail/monodroid/2012-May/010250.html

Thanks,
 - Jon

_______________________________________________
Monodroid mailing list
Monodroid@lists.ximian.com

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

Reply via email to