Bug 3781 - Using SimpleExpandableListAdapter twice.
Summary: Using SimpleExpandableListAdapter twice.
Status: RESOLVED FIXED
Alias: None
Product: Android
Classification: Xamarin
Component: BCL Class Libraries ()
Version: 4.0
Hardware: Macintosh Mac OS
: Normal normal
Target Milestone: ---
Assignee: Jonathan Pryor
URL:
Depends on:
Blocks:
 
Reported: 2012-03-07 06:09 UTC by Maxim
Modified: 2012-03-12 04:38 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Demo project (376.50 KB, application/x-zip)
2012-03-07 06:09 UTC, Maxim
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Maxim 2012-03-07 06:09:15 UTC
Created attachment 1467 [details]
Demo project

On activity I have ExpandableListView, which using SimpleExpandableListAdapter.

When I run second time, it crashed with unhandled error.

I checked all data types and conditions, then tried to use http://stackoverflow.com/questions/3053761/reload-activity-in-android example - same error.

Demo project included.

Stack:
I/mono    (  612): Stacktrace:
I/mono    (  612): 
I/mono    (  612):   at Android.Runtime.JNIEnv.NewGlobalRef (intptr) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JNIEnv.cs:311
I/mono    (  612):   at Java.Lang.Object.RegisterInstance (Android.Runtime.IJavaObject,intptr,Android.Runtime.JniHandleOwnership) [0x00041] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Java.Lang/Object.cs:138
I/mono    (  612):   at Java.Lang.Object.SetHandle (intptr,Android.Runtime.JniHandleOwnership) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Java.Lang/Object.cs:122
I/mono    (  612):   at Java.Lang.String..ctor (string) [0x000a7] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/platforms/android-10/src/generated/Java.Lang.String.cs:73
I/mono    (  612):   at Android.Runtime.JavaTypeConverter`1/Convert.ToJavaObject (string) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaTypeConverter.cs:166
I/mono    (  612):   at Android.Runtime.JavaTypeConverter`1/ObjectConverter`1.<toJavaObjectConverters>m__50 (object) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaTypeConverter.cs:476
I/mono    (  612):   at Android.Runtime.JavaTypeConverter`1/ObjectConverter`1.ToNative (O) [0x0002b] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaTypeConverter.cs:486
I/mono    (  612):   at Android.Runtime.JavaDictionary`2.Add (K,V) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaDictionary.cs:300
I/mono    (  612):   at Android.Runtime.JavaDictionary`2..ctor (System.Collections.Generic.IDictionary`2<K, V>) [0x00035] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaDictionary.cs:271
I/mono    (  612):   at (wrapper runtime-invoke) <Module>.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <IL 0x00052, 0xffffffff>
I/mono    (  612):   at System.Reflection.MonoCMethod.Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00109] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:536
I/mono    (  612):   at System.Reflection.MonoCMethod.Invoke (System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:551
I/mono    (  612):   at System.Activator.CreateInstance (System.Type,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo,object[]) [0x00174] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:299
I/mono    (  612):   at System.Activator.CreateInstance (System.Type,object[],object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:234
I/mono    (  612):   at System.Activator.CreateInstance (System.Type,object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:229
I/mono    (  612):   at Android.Runtime.JavaTypeConverter`1/JavaGenericDictionaryConverter`1.ToNative (GD) [0x0003b] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaTypeConverter.cs:325
I/mono    (  612):   at Android.Runtime.JavaList`1.Add (T) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:269
I/mono    (  612):   at Android.Runtime.JavaList`1..ctor (System.Collections.Generic.IEnumerable`1<T>) [0x00030] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:255
I/mono    (  612):   at (wrapper runtime-invoke) <Module>.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <IL 0x00052, 0xffffffff>
I/mono    (  612):   at System.Reflection.MonoCMethod.Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00109] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:536
I/mono    (  612):   at System.Reflection.MonoCMethod.Invoke (System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:551
I/mono    (  612):   at System.Activator.CreateInstance (System.Type,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo,object[]) [0x00174] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:299
I/mono    (  612):   at System.Activator.CreateInstance (System.Type,object[],object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:234
I/mono    (  612):   at System.Activator.CreateInstance (System.Type,object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:229
I/mono    (  612):   at Android.Runtime.JavaTypeConverter`1/JavaGenericListConverter`1.ToNative (GL) [0x0003b] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaTypeConverter.cs:349
I/mono    (  612):   at Android.Runtime.JavaList`1.Add (T) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:269
I/mono    (  612):   at Android.Runtime.JavaList`1..ctor (System.Collections.Generic.IEnumerable`1<T>) [0x00030] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:255
I/mono    (  612):   at Android.Runtime.JavaList`1.ToNative (System.Collections.Generic.IList`1<T>) [0x00023] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:341
I/mono    (  612):   at Android.Runtime.JavaList`1.ToJniHandle (System.Collections.Generic.IList`1<T>) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:330
I/mono    (  612):   at Android.Widget.SimpleExpandableListAdapter..ctor (Android.Content.Context,System.Collections.Generic.IList`1<System.Collections.Generic.IDictionary`2<string, object>>,int,string[],int[],System.Collections.Generic.IList`1<System.Collections.Generic.IList`1<System.Collections.Generic.IDictionary`2<string, object>>>,int,string[],int[]) [0x001aa] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/platforms/android-10/src/generated/Android.Widget.SimpleExpandableListAdapter.cs:56
I/mono    (  612):   at And.expandable_list_test.OnCreate (Android.OS.Bundle) [0x0010f] in /Users/fvs/Projects/And/And/expandable_list_test.cs:76
I/mono    (  612):   at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) [0x00010] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/platforms/android-10/src/generated/Android.App.Activity.cs:1438
I/mono    (  612):   at (wrapper dynamic-method) object.3f71d49c-2ba1-41bd-8e75-99a5f8f2dd47 (intptr,intptr,intptr) <IL 0x00012, 0x00033>
I/mono    (  612):   at (wrapper native-to-managed) object.3f71d49c-2ba1-41bd-8e75-99a5f8f2dd47 (intptr,intptr,intptr) <IL 0x0001f, 0xffffffff>
Comment 1 Maxim 2012-03-07 06:22:24 UTC
"When I run second time" - I mean, when I call activity with SimpleExpandableListAdapter from main activity, then press back button, then call it again.
Comment 2 Jonathan Pryor 2012-03-07 16:57:42 UTC
Is this on the emulator or hardware?

If this is the emulator, the emulator has a limited number of global references, and your construction code consumes a lot of them (~1552 out of 2000):

> $ adb shell setprop debug.mono.log gref
> $ adb logcat...
> # launch your app...
> ...
> I/monodroid-gref(20025): +g+ grefc 12 gwrefc 0 obj-handle 0x4051e980/L -> new-handle 0x4051e980/L from    at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
> ...
> 
> # Tap the "Hello World, Click Me!" button
> ...
> I/monodroid-gref(20257): +g+ grefc 1552 gwrefc 0 obj-handle 0x40546188/L -> new-handle 0x40546188/L from    at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)

Clicking the Back button will not prompt a GC, so when you click the button again the runtime will try to create another ~1550 global references, which will kill the emulator. A potential fix is to override Activity.OnDestroy() and kick the GC:

	partial class expandable_list_test {

		protected override void OnDestroy ()
		{
			base.OnDestroy ();
			Console.WriteLine ("# OnDestroy; collecting!");
			System.GC.Collect ();
		}
	}

The above allows the app to work for me.
Comment 3 Maxim 2012-03-08 01:59:58 UTC
Thank you!

Yes. This is emulator of Android 2.3 device.

Please explain some tech details:
1. Is it possible to simply increase number of global references in emulator?
2. Why private, prepared for expandablelistview data transforms to global references?
3. What if expandablelistview will contains more groups and items? App will crash anytime on activity start?


I tried your solution. Unfortunately with no changes: 

I/mono-stdout(  649): # OnDestroy; collecting!
I/monodroid-gc(  649): GC cleanup summary: 1629 objects tested - resurrecting 1628.
I/mono    (  649): Stacktrace:
I/mono    (  649): 
I/mono    (  649):   at Android.Runtime.JNIEnv.NewGlobalRef (intptr) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JNIEnv.cs:311
I/mono    (  649):   at Android.Runtime.JNIEnv.FindClass (string) [0x0007d] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JNIEnv.cs:240
I/mono    (  649):   at Android.Runtime.JNIEnv.CreateInstance (string,string,Android.Runtime.JValue[]) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JNIEnv.cs:170
I/mono    (  649):   at Android.Runtime.JavaDictionary`2..ctor () [0x00021] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaDictionary.cs:252
I/mono    (  649):   at Android.Runtime.JavaDictionary`2..ctor (System.Collections.Generic.IDictionary`2<K, V>) <IL 0x00001, 0x0005b>
I/mono    (  649):   at (wrapper runtime-invoke) <Module>.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <IL 0x00052, 0xffffffff>
I/mono    (  649):   at System.Reflection.MonoCMethod.Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00109] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:536
I/mono    (  649):   at System.Reflection.MonoCMethod.Invoke (System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:551
I/mono    (  649):   at System.Activator.CreateInstance (System.Type,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo,object[]) [0x00174] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:299
I/mono    (  649):   at System.Activator.CreateInstance (System.Type,object[],object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:234
I/mono    (  649):   at System.Activator.CreateInstance (System.Type,object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:229
I/mono    (  649):   at Android.Runtime.JavaTypeConverter`1/JavaGenericDictionaryConverter`1.ToNative (GD) [0x0003b] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaTypeConverter.cs:325
I/mono    (  649):   at Android.Runtime.JavaList`1.Add (T) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:269
I/mono    (  649):   at Android.Runtime.JavaList`1..ctor (System.Collections.Generic.IEnumerable`1<T>) [0x00030] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:255
I/mono    (  649):   at (wrapper runtime-invoke) <Module>.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <IL 0x00052, 0xffffffff>
I/mono    (  649):   at System.Reflection.MonoCMethod.Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00109] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:536
I/mono    (  649):   at System.Reflection.MonoCMethod.Invoke (System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:551
I/mono    (  649):   at System.Activator.CreateInstance (System.Type,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo,object[]) [0x00174] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:299
I/mono    (  649):   at System.Activator.CreateInstance (System.Type,object[],object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:234
I/mono    (  649):   at System.Activator.CreateInstance (System.Type,object[]) [0x00000] in /home/jon/Development/xamarin/mono/mcs/class/corlib/System/Activator.cs:229
I/mono    (  649):   at Android.Runtime.JavaTypeConverter`1/JavaGenericListConverter`1.ToNative (GL) [0x0003b] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaTypeConverter.cs:349
I/mono    (  649):   at Android.Runtime.JavaList`1.Add (T) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:269
I/mono    (  649):   at Android.Runtime.JavaList`1..ctor (System.Collections.Generic.IEnumerable`1<T>) [0x00030] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:255
I/mono    (  649):   at Android.Runtime.JavaList`1.ToNative (System.Collections.Generic.IList`1<T>) [0x00023] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:341
I/mono    (  649):   at Android.Runtime.JavaList`1.ToJniHandle (System.Collections.Generic.IList`1<T>) [0x00000] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/src/Runtime/JavaList.cs:330
I/mono    (  649):   at Android.Widget.SimpleExpandableListAdapter..ctor (Android.Content.Context,System.Collections.Generic.IList`1<System.Collections.Generic.IDictionary`2<string, object>>,int,string[],int[],System.Collections.Generic.IList`1<System.Collections.Generic.IList`1<System.Collections.Generic.IDictionary`2<string, object>>>,int,string[],int[]) [0x001aa] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/platforms/android-10/src/generated/Android.Widget.SimpleExpandableListAdapter.cs:56
I/mono    (  649):   at And.expandable_list_test.OnCreate (Android.OS.Bundle) [0x0010f] in /Users/fvs/Projects/And/And/expandable_list_test.cs:76
I/mono    (  649):   at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) [0x00010] in /Users/jon/Development/xamarin/monodroid-hotfix/Mono.Android/platforms/android-10/src/generated/Android.App.Activity.cs:1438
I/mono    (  649):   at (wrapper dynamic-method) object.ff1e1a43-b34a-450a-906e-38159a6512e2 (intptr,intptr,intptr) <IL 0x00012, 0x00033>
I/mono    (  649):   at (wrapper native-to-managed) object.ff1e1a43-b34a-450a-906e-38159a6512e2 (intptr,intptr,intptr) <IL 0x0001f, 0xffffffff>
Comment 4 Jonathan Pryor 2012-03-08 14:14:34 UTC
> 1. Is it possible to simply increase number of global references in emulator?

Not that I am aware of.

> 2. Why private, prepared for expandablelistview data transforms to global references?

Android needs Java-side object references in order to render _anything_, so as part of the SimpleExpandableListAdapter creation we need to marshal the entire object graph to an equivalent Java-side object graph. Creating the marshaled object graph requires global references; arguably we could dispose of some of them earlier than we currently do. I'll look into improving this for a future release.

> 3. What if expandablelistview will contains more groups and items? App will crash anytime on activity start?

Yup. Alternatively, don't use SimpleExpandableListAdapter, but instead provide your own BaseAdapter subclass, e.g.

https://github.com/xamarin/monodroid-samples/blob/master/ApiDemo/Tutorials/GalleryTutorial.cs#L30
https://github.com/xamarin/monodroid-samples/blob/master/ApiDemo/Tutorials/GridViewTutorial.cs#L28
https://github.com/xamarin/monodroid-samples/blob/master/LabelledSections/SeparatedListAdapter.cs#L12

Implementing your own BaseAdapter allows you to create items on-demand (instead of creating the entire object graph at once), and also allows reusing instances:

http://androidapi.xamarin.com/?link=M:Android.Widget.IAdapter.GetView

Reusing an existing View instance can keep the global reference count lower, reduce memory use, and allow things to go faster.

> I tried your solution. Unfortunately with no changes: 

Hm, sorry about that. Instead, try calling GC.Collect() in your `button.Click` handler within MainMenu.OnCreate(), before the StartActivity() call:


	button.Click += delegate {
		GC.Collect ();
		StartActivity(new Intent(this, typeof(expandable_list_test)));
	};

If you enable GC logging:

    $ adb shell setprop debug.mono.log gc

It'll prompt a collection every time you tab the button:

> I/monodroid-gc(21344): GC cleanup summary: 1627 objects tested - resurrecting 1.

That should make things work better.
Comment 5 Maxim 2012-03-09 02:57:36 UTC
Wow! Thank you. It is very exhaustive and descriptive. 

Now, if move GC.Collect to button's click handler, app don't crash when open second activity many times. It crashed only if I open group elements to see nested elements. Much better.

Yes. I'll create BaseAdapter subclass. It's very simple, cause we already have such classes in our project and cause this idea very close to iOS's tableViewSource, which we already create much in iOS port of app.

Please wait until 03/13 to close this issue.
Comment 6 Maxim 2012-03-11 10:10:33 UTC
I tried to implement custom adapter based on https://github.com/xamarin/monodroid-samples/blob/master/LabelledSections/SeparatedListAdapter.cs#L12 example (cause I need groups/sections in listview).

But how to implement OnItemClick handler? And how to get item index in it's own group?
Comment 7 Maxim 2012-03-12 04:38:51 UTC
Ok, I done it via implementing ListView's ItemClick handler and my own function, which convert absolute index in SeparatedListAdapter to section's index + item in section index (just like on iOS).

Thank you.