Troubleshooting

PDF for offline use

Let us know how you feel about this

Translation Quality


0/250

last updated: 0201-05

Getting Diagnostic Information

Xamarin.Android has a few places to look when tracking down various bugs. These include:

  1. Diagnostic MSBuild output.
  2. Device deployment logs.
  3. Android Debug Log Output.

Diagnostic MSBuild Output

Diagnostic MSBuild can contain additional information relating to package building and may contain some package deployment information.

To enable diagnostic MSBuild output within Visual Studio:

  1. Click Tools > Options...
  2. In the left-hand tree view, select Projects and Solutions > Build and Run
  3. In the right-hand panel, set the MSBuild build output verbosity dropdown to Diagnostic
  4. Click OK
  5. Clean and rebuild your package.
  6. Diagnostic output is visible within the Output panel.

To enable diagnostic MSBuild output within Xamarin Studio/OS X:

  1. Click Xamarin Studio > Preferences...
  2. In the left-hand tree view, select Projects > Build
  3. In the right-hand panel, set the Log verbosity drop-down to Diagnostic
  4. Click OK
  5. Restart Xamarin Studio
  6. Clean and rebuild your package.
  7. Diagnostic output is visible within the Errors Pad ( View > Pads > Errors ), by clicking the Build Output button.

Device Deployment Logs

To enable device deployment logging within Visual Studio:

  1. Tools > Options...>
  2. In the left-hand tree view, select Xamarin > Android Settings
  3. In the right-hand panel, enable the [X] extension debug logging (writes monodroid.log to your desktop) check box.
  4. Log messages are written to the monodroid.log file on your desktop.

Xamarin Studio always writes device deployment logs. FInding them is slightly more difficult; a AndroidUtils log file is created for every day + time that a deployment occurs, e.g.  AndroidTools-2012-10-24__12-35-45.log.

  • On Windows, log files are written to  %LOCALAPPDATA%\XamarinStudio-{VERSION}\Logs .
  • On OS X, log files are written to  $HOME/Library/Logs/XamarinStudio-{VERSION} .

Android Debug Log Output

Android will write many messages to the Android Debug Log. Xamarin.Android uses Android system properties to control the generation of additional messages to the Android Debug Log. Android system properties can be set through the setprop command within the Android Debug Bridge (adb):

adb shell setprop PROPERTY_NAME PROPERTY_VALUE

System properties are read during process startup, and thus must be either set before the application is launched or the application must be restarted after the system properties are changed.

Xamarin.Android System Properties

Xamarin.Android supports the following system properties:

  • debug.mono.debug: If a non-empty string, this is equivalent to `mono --debug`.
  • debug.mono.env: A pipe-separated ('|') list of environment variables to export during application startup, before mono has been initialized. This allows setting environment variables that control mono logging.
    • Note: Since the value is '|'-separated, the value must have an extra level of quoting, as the `adb shell` command will remove a set of quotes.
    • Note: Android system property values can be no longer than 92 characters in length.
    • Example:

      adb shell setprop debug.mono.env "'MONO_LOG_LEVEL=info|MONO_LOG_MASK=asm'"
  • debug.mono.log: A comma-separated (',') list of components that should print additional messages to the Android Debug Log. By default, nothing is set. Components include:
    • all: Print all messages
    • gc: Print GC-related messages.
    • gref: Print (weak, global) reference allocation and deallocation messages.
    • lref: Print local reference allocation and deallocation messages.
      • Note: these are extremely verbose. Do not enable unless you really need to.
  • debug.mono.trace: Allows setting the `mono --trace=PROPERTY_VALUE` setting.

Xamarin.Android cannot resolve System.ValueTuple

This error occurs due to an incompatibility with Visual Studio.

  • Visual Studio 2017 Update 1 (version 15.1 or older) is only compatible with the System.ValueTuple NuGet 4.3.0 (or older).

  • Visual Studio 2017 Update 2 (version 15.2 or newer) is only compatible with the System.ValueTuple NuGet 4.3.1 (or newer).

Please choose the correct System.ValueTuple NuGet that corresponds with your Visual Studio 2017 installation.

GC Messages

GC component messages can be viewed by setting the debug.mono.log system property to a value that contains gc.

GC messages are generated whenever the GC executes and provides information about how much work the GC did:

I/monodroid-gc(12331): GC cleanup summary: 81 objects tested - resurrecting 21.

Additional GC information such as timing information can be generated by setting the MONO_LOG_LEVEL environment variable to debug:

adb shell setprop debug.mono.env MONO_LOG_LEVEL=debug

This will result in (lots of) additional Mono messages, including these three of consequence:

D/Mono (15723): GC_BRIDGE num-objects 1 num_hash_entries 81226 sccs size 81223 init 0.00ms df1 285.36ms sort 38.56ms dfs2 50.04ms setup-cb 9.95ms free-data 106.54ms user-cb 20.12ms clenanup 0.05ms links 5523436/5523436/5523096/1 dfs passes 1104 6883/11046605
D/Mono (15723): GC_MINOR: (Nursery full) pause 2.01ms, total 287.45ms, bridge 225.60 promoted 0K major 325184K los 1816K
D/Mono ( 2073): GC_MAJOR: (user request) pause 2.17ms, total 2.47ms, bridge 28.77 major 576K/576K los 0K/16K

In the GC_BRIDGE message, num-objects is the number of bridge objects this pass is considering, and num_hash_entries is the number of objects processed during this invocation of the bridge code.

In the GC_MINOR and GC_MAJOR messages, total is the amount of time while the world is paused (no threads are executing), while bridge is the amount of time taken in the bridge processing code (which deals with the Java VM). The world is not paused while bridge processing occurs.

In general, the larger the value of num_hash_entries, the more time that the bridge collections will take, and the larger the total time spent collecting will be.

Global Reference Messages

To enable Global Reference loggig (GREF) logging, the debug.mono.log system property must contain gref, e.g.:

adb shell setprop debug.mono.log gref

Xamarin.Android uses Android global references to provide mappings between Java instances and the associated managed instances, as when invoking a Java method a Java instance needs to be provided to Java.

Unfortunately, Android emulators only allow 2000 global references to exist at a time. Hardware has a much higher limit of 52000 global references. The lower limit can be problematic when running applications on the emulator, so knowing where the instance came from can be very useful.

Note: the global reference count is internal to Xamarin.Android, and does not (and cannot) include global references taken out by other native libraries loaded into the process. Use the global reference count as an estimate.

I/monodroid-gref(12405): +g+ grefc 108 gwrefc 0 obj-handle 0x40517468/L -> new-handle 0x40517468/L from    at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable)
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)
I/monodroid-gref(12405):    at Android.App.Activity.RunOnUiThread(System.Action action)
I/monodroid-gref(12405):    at Mono.Samples.Hello.HelloActivity.UseLotsOfMemory(Android.Widget.TextView textview)
I/monodroid-gref(12405):    at Mono.Samples.Hello.HelloActivity.<OnCreate>m__3(System.Object o)
I/monodroid-gref(12405): handle 0x40517468; key_handle 0x40517468: Java Type: `mono/java/lang/RunnableImplementor`; MCW type: `Java.Lang.Thread+RunnableImplementor`
I/monodroid-gref(12405): Disposing handle 0x40517468
I/monodroid-gref(12405): -g- grefc 107 gwrefc 0 handle 0x40517468/L from    at Java.Lang.Object.Dispose(System.Object instance, IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
I/monodroid-gref(12405):    at Java.Lang.Object.Dispose()
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor.Run()
I/monodroid-gref(12405):    at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
I/monodroid-gref(12405):    at System.Object.c200fe6f-ac33-441b-a3a0-47659e3f6750(IntPtr , IntPtr )
I/monodroid-gref(27679): +w+ grefc 1916 gwrefc 296 obj-handle 0x406b2b98/G -> new-handle 0xde68f4bf/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1915 gwrefc 294 handle 0xde691aaf/W from take_global_ref_jni

There are four messages of consequence:

  • Global reference creation: these are the lines that start with +g+ , and will provide a stack trace for the creating code path.
  • Global reference destruction: these are the lines that start with -g- , and may provide a stack trace for the code path disposing of the global reference. If the GC is disposing of the gref, no stack trace will be provided.
  • Weak global reference creation: these are the lines that start with +w+ .
  • Weak global reference destruction: these are lines that start with -w- .

In all messages, The grefc value is the count of global references that Xamarin.Android has created, while the grefwc value is the count of weak global references that Xamarin.Android has created. The handle or obj-handle value is the JNI handle value, and the character after the ' /' is the type of handle value: /L for local reference, /G for global references, and /W for weak global references.

As part of the GC process, global references (+g+) are converted into weak global references (causing a +w+ and -g-), a Java-side GC is kicked, and then the weak global reference is checked to see if it was collected. If it's still alive, a new gref is created around the weak ref (+g+, -w-), otherwise the weak ref is destroyed (-w).

# Java instance is created and wrapped by a MCW
I/monodroid-gref(27679): +g+ grefc 2211 gwrefc 0 obj-handle 0x4066df10/L -> new-handle 0x4066df10/L from ...
I/monodroid-gref(27679): handle 0x4066df10; key_handle 0x4066df10: Java Type: `android/graphics/drawable/TransitionDrawable`; MCW type: `Android.Graphics.Drawables.TransitionDrawable`

# A GC is being performed...
I/monodroid-gref(27679): +w+ grefc 1953 gwrefc 259 obj-handle 0x4066df10/G -> new-handle 0xde68f95f/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -g- grefc 1952 gwrefc 259 handle 0x4066df10/G from take_weak_global_ref_jni

# Object is still alive, as handle != null
# wref turned back into a gref
I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x4066df10
I/monodroid-gref(27679): +g+ grefc 1930 gwrefc 39 obj-handle 0xde68f95f/W -> new-handle 0x4066df10/G from take_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1930 gwrefc 38 handle 0xde68f95f/W from take_global_ref_jni

# Object is dead, as handle == null
# wref is freed, no new gref created
I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x0
I/monodroid-gref(27679): -w- grefc 1914 gwrefc 296 handle 0xde68f95f/W from take_global_ref_jni

There is one "interesing" wrinkle here: on targets running Android prior to 4.0, the gref value is equal to the address of the Java object in the Android runtime's memory. (That is, the GC is a non-moving, conservative, collector, and it's handing out direct references to those objects.) Thus after a +g+, +w+, -g-, +g+, -w- sequence, the resulting gref will have the same value as the original gref value. This makes grepping through logs fairly straightforward.

Android 4.0, however, has a moving collector and no longer hands out direct references to Android runtime VM objects. Consequently, after a +g+, +w+, -g-, +g+, -w- sequence, the gref value will be different. If the object survives multiple GCs, it will go by several gref values, making it harder to determine where an instance was actually allocated from.

Querying Programmatically

You can query both the GREF and WREF counts by querying the JniRuntime object.

Java.Interop.JniRuntime.CurrentRuntime.GlobalReferenceCount - Global Reference Count

Java.Interop.JniRuntime.CurrentRuntime.WeakGlobalReferenceCount - Weak Reference Count

Offline Activation

If you're unable to activate Xamarin.Android on Windows, or unable to install the full version of Xamarin.Android on Mac OS X, please see the Offline Activation page.

Can't upgrade to Indie/Business from Trial Account

If you recently purchased Xamarin.Android and previously started a Xamarin.Android Trial, you may need to complete the following steps to get this license change picked up by Xamarin Studio or Visual Studio.

  • Close Xamarin Studio/Visual Studio
  • Remove all files from ~/Library/MonoAndroid on Mac or %PROGRAMDATA%\Mono for Android\License\ for Windows
  • Re-open Xamarin Studio/Visual Studio and build a Xamarin.Android project

This should get you up and running. If you continue to have problems, you may want to try an Offline Activation to complete the activation of your workstation.

Receiving 'Activation Incomplete Error Message

This issue may occur when using Xamarin.Android for Visual Studio. To resolve this issue, please send the logs from the following location to contact@xamarin.com.

  • Log location: %LocalAppData%\Xamarin\Logs

Receiving 'Error Retrieving Update Information' Error Message

From time to time, an update will fail with this following error, which will often occur when checking for updates:

A majority of the time, this error can be resolved simply by logging out of your Xamarin account, and then logging back in.

To accomplish this, please find your platform of choice below and follow the steps:

On Mac: 1. Open Xamarin Studio 2. Select Xamarin Studio > Account... 3. Click Log Out 4. Click Log In 5. Enter Your Credentials 6. Check for Updates

On PC using Xamarin Studio: 1. Open Xamarin Studio 2. Select Tools > Account 3. Click Log Out 4. Click Log In 5. Enter Your Credentials 6. Check for Updates

On PC using Visual Studo: 1. Open Visual Studio 2. Select Tools > Xamarin Account 3. Click Log Out 4. Click Log In 5. Enter Your Credentials 6. Check for Updates

If this error message continues to appear, please e-mail contact@xamarin.com.

Receiving 'Invalid License' Error Message

This error message may appear if the user attempting to activate a workstation has not been invited to a seat. This may be resolved by the account manager logging into their Xamarin Store Account and selecting ‘Manage Subscriptions’.

Once the account holder has invited a developer to a seat, the developer may then sign into the IDE and activate successfully.

Android Debug Logs

The Android Debug Logs may provide additional context regarding any runtime errors you're seeing.

Floating-Point performance is terrible!

Alternatively, "My app runs 10x faster with the Debug build than with the Release build!"

Xamarin.Android supports multiple device ABIs: armeabi, armeabi-v7a, and x86. Device ABIs can be specified within Project Properties > Application tab > Supported architectures.

Debug builds use an Android package which provides all ABIs, and thus will use the fastest ABI for the target device.

Release builds will only include the ABIs selected in the Project Properties tab. More than one can be selected.

armeabi is the default ABI, and has the broadest device support. However, armeabi doesn't support multi-CPU devices and hardware floating-point, amont other things. Consequently, apps using the armeabi Release runtime will be tied to a single core and will be using a soft-float implementation. Both of these can contribute to significantly slower performance for your app.

If your app requires decent floating-point performance (e.g. games), you should enable the armeabi-v7a ABI. You may want to only support the armeabi-v7a runtime, though this means that older devices which only support armeabi will be unable to run your app.

Could not locate Android SDK

There are 2 downloads available from Google for the Android SDK for Windows. If you choose the .exe installer, it will write registry keys that tell Xamarin.Android where it was installed. If you choose the .zip file and unzip it yourself, Xamarin.Android does not know where to look for the SDK. You can tell Xamarin.Android where the SDK is in Visual Studio by going to Tools

-> Options

-> Xamarin -> Android Settings

, or in Xamarin Studio by going to Xamarin Studio -> Preferences -> SDK Locations:

IDE does not display target device

Sometimes you will attempt to deploy your application to a device, but the device you want to deploy to isn't shown in the Select Device dialog. This can happen when the Android Debug Bridge decides to go on vacation.

To diagnose this issue, find the adb program, then run:

adb devices

If your device isn't present, then you need to restart the Android Debug Bridge server so that your device can be found:

adb kill-server
adb start-server

HTC Sync software may prevent `adb start-server` from working properly. If the `adb start-server` command doesn't print out which port it's starting on, please exit the HTC Sync software and try restarting the adb server.

The specified task executable "keytool" could not be run

This means that your PATH does not contain the directory where the Java SDK's bin directory is located. Check that you followed those steps from the Installation guide.

monodroid.exe or aresgen.exe exited with code 1

To help you debug this problem, go into Visual Studio and change the MSBuild verbosity level, to do this, select: Tools->Options->Project and Solutions->Build and Run->MSBuild Project Build Output Verbosity and set this value to Normal.

Rebuild, and check Visual Studio's Output pane, which should contain the full error.

There is not enough storage space on the device to deploy the package

This occurs when you don't start the emulator from within Visual Studio. When starting the emulator outside of Visual Studio, you need to pass the -partition-size 512 options, e.g.

emulator -partition-size 512 -avd MonoDroid

Ensure you use the correct simulator name, i.e. the name you used when configuring the simulator.

INSTALL_FAILED_INVALID_APK when installing a package

Android package names must contain a period ('.'). Edit your package name so that it contains a period.

  • Within Visual Studio:
    • Right click your project > Properties
    • Click the Android Manifest tab on the left.
    • Update the Package name field.
      • If you see the message "No AndroidManifest.xml found. Click to add one.", click the link and then update the Package name field.
  • Within Xamarin Studio:
    • Right click your project > Options.
    • Navigate to the Build / Android Application section.
    • Change the Package name field to contain a '.'.

INSTALL_FAILED_MISSING_SHARED_LIBRARY when installing a package

A "shared library" in this context is not a native shared library (libfoo.so) file; it is instead a library that must be separately installed on the target device, such as Google Maps.

The Android package specifies which shared libraries are required with the <uses-library/> element. If a required library is not present on the target device (e.g. //uses-library/@android:required is true, which is the default), then package installation will fail with INSTALL_FAILED_MISSING_SHARED_LIBRARY.

To determine which shared libraries are required, view the generated AndroidManifest.xml file (e.g. obj\Debug\android\AndroidManifest.xml) and look for the <uses-library/> elements. <uses-library/> elements can be added manually in your project's Properties\AndroidManifest.xml file and via the UsesLibraryAttribute custom attribute.

For example, adding an assembly reference to Mono.Android.GoogleMaps.dll will implicitly add a <uses-library/> for the Google Maps shared library.

INSTALL_FAILED_UPDATE_INCOMPATIBLE when installing a package

Android packages have three requirements:

  • They must contain a '.' (see previous entry)
  • They must have a unique string package name (hence the reverse-tld convention seen in Android app names, e.g. com.android.chrome for the Chrome app)
  • When upgrading packages, the package must have the same signing key.

Thus, imagine this scenario:

  1. You build & deploy your app as a Debug app
  2. You change the signing key, e.g. to use as a Release app (or because you don't like the default-provided Debug signing key)
  3. You install your app without removing it first, e.g. Debug > Start Without Debugging within Visual Studio

When this happens, package installation will fail with a INSTALL_FAILED_UPDATE_INCOMPATIBLE error, because the package name didn't change while the signing key did. The Android Debug Log will also contain a message similar to:

E/PackageManager(  146): Package [PackageName] signatures do not match the previously installed version; ignoring!

To fix this error, completely remove the application from your device before re-installing.

INSTALLFAILEDUID_CHANGED when installing a package

When an Android package is installed, it is assigned a user id (UID). Sometimes, for currently unknown reasons, when installing over an already installed app, the installation will fail with INSTALL_FAILED_UID_CHANGED:

ERROR [2015-03-23 11:19:01Z]: ANDROID: Deployment failed
Mono.AndroidTools.InstallFailedException: Failure [INSTALL_FAILED_UID_CHANGED]
   at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName)
   at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass2c.<InstallPackage>b__2b(Task`1 t)
   at System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

To work around this issue, fully uninstall the Android package, either by installing the app from the Android target's GUI, or using adb:

$ adb uninstall @PACKAGE_NAME@

DO NOT USE adb uninstall -k, as this will preserve application data, and thus preserve the conflicting UID on the target device.

Release apps fail to launch on device

Does the Android Debug Log output will contain a message similar to:

D/AndroidRuntime( 1710): Shutting down VM
W/dalvikvm( 1710): threadid=1: thread exiting with uncaught exception (group=0xb412f180)
E/AndroidRuntime( 1710): FATAL EXCEPTION: main
E/AndroidRuntime( 1710): java.lang.UnsatisfiedLinkError: Couldn't load monodroid: findLibrary returned null
E/AndroidRuntime( 1710):        at java.lang.Runtime.loadLibrary(Runtime.java:365)

If so, there are two possible causes for this:

  1. The .apk doesn't provide an ABI that the target device supports. For example, the .apk only contains armeabi-v7a binaries, and the target device only supports armeabi.
  2. An Android bug. If this is the case, uninstall the app, cross your fingers, and reinstall the app.

To fix (1), edit the Project Options/Properties and add support for the required ABI to the list of Supported ABIs. To determine which ABI you need to add, run the following adb command against your target device:

adb shell getprop ro.product.cpu.abi
adb shell getprop ro.product.cpu.abi2

The output will contain the primary (and optional secondary) ABIs.

$ adb shell getprop | grep ro.product.cpu
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abi]: [armeabi-v7a]

The OutPath property is not set for project "MyApp.csproj"

This generally means you have an HP computer and the environment variable "Platform" has been set to something like MCD or HPD. This conflicts with the MSBuild Platform property that is generally set to "Any CPU" or "x86".



You will need to remove this environment variable from your machine before MSBuild can function:

  • Control Panel > System > Advanced > Environment Variables

Restart Visual Studio or Xamarin Studio and try to rebuild. Things should now work as expected.

java.lang.ClassCastException: mono.android.runtime.JavaObject cannot be cast to...

Xamarin.Android 4.x doesn't properly marshal nested generic types properly. For example, consider the following C# code using SimpleExpandableListAdapter:

// BAD CODE; DO NOT USE
var groupData = new List<IDictionary<string, object>> () {
        new Dictionary<string, object> {
                { "NAME", "Group 1" },
                { "IS_EVEN", "This group is odd" },
        },
};
var childData = new List<IList<IDictionary<string, object>>> () {
        new List<IDictionary<string, object>> {
                new Dictionary<string, object> {
                        { "NAME", "Child 1" },
                        { "IS_EVEN", "This group is odd" },
                },
        },
};
mAdapter = new SimpleExpandableListAdapter (
        this,
        groupData,
        Android.Resource.Layout.SimpleExpandableListItem1,
        new string[] { "NAME", "IS_EVEN" },
        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
        childData,
        Android.Resource.Layout.SimpleExpandableListItem2,
        new string[] { "NAME", "IS_EVEN" },
        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
);

The problem is that Xamarin.Android incorrectly marshals nested generic types. The List<IDictionary<string, object>> is being marshaled to a java.lang.ArrrayList, but the ArrayList is containing mono.android.runtime.JavaObject instances (which reference the Dictionary<string, object> instances) instead of something that implements java.util.Map, resulting in the following exception:

E/AndroidRuntime( 2991): FATAL EXCEPTION: main
E/AndroidRuntime( 2991): java.lang.ClassCastException: mono.android.runtime.JavaObject cannot be cast to java.util.Map
E/AndroidRuntime( 2991):        at android.widget.SimpleExpandableListAdapter.getGroupView(SimpleExpandableListAdapter.java:278)
E/AndroidRuntime( 2991):        at android.widget.ExpandableListConnector.getView(ExpandableListConnector.java:446)
E/AndroidRuntime( 2991):        at android.widget.AbsListView.obtainView(AbsListView.java:2271)
E/AndroidRuntime( 2991):        at android.widget.ListView.makeAndAddView(ListView.java:1769)
E/AndroidRuntime( 2991):        at android.widget.ListView.fillDown(ListView.java:672)
E/AndroidRuntime( 2991):        at android.widget.ListView.fillFromTop(ListView.java:733)
E/AndroidRuntime( 2991):        at android.widget.ListView.layoutChildren(ListView.java:1622)

The workaround is to use the provided Java Collection types instead of the System.Collections.Generic types for the "inner" types. This will result in appropriate Java types when marshaling the instances. (The following code is more complicated than necessary in order to reduce gref lifetimes. It can be simplified to altering the original code via s/List/JavaList/g and s/Dictionary/JavaDictionary/g if gref lifetimes aren't a worry.)

// insert good code here
using (var groupData = new JavaList<IDictionary<string, object>> ()) {
        using (var groupEntry = new JavaDictionary<string, object> ()) {
                groupEntry.Add ("NAME", "Group 1");
                groupEntry.Add ("IS_EVEN", "This group is odd");
                groupData.Add (groupEntry);
        }
        using (var childData = new JavaList<IList<IDictionary<string, object>>> ()) {
                using (var childEntry = new JavaList<IDictionary<string, object>> ())
                using (var childEntryDict = new JavaDictionary<string, object> ()) {
                        childEntryDict.Add ("NAME", "Child 1");
                        childEntryDict.Add ("IS_EVEN", "This child is odd.");
                        childEntry.Add (childEntryDict);
                        childData.Add (childEntry);
                }
                mAdapter = new SimpleExpandableListAdapter (
                        this,
                        groupData,
                        Android.Resource.Layout.SimpleExpandableListItem1,
                        new string[] { "NAME", "IS_EVEN" },
                        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
                        childData,
                        Android.Resource.Layout.SimpleExpandableListItem2,
                        new string[] { "NAME", "IS_EVEN" },
                        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
                );
        }
}

This will be fixed in a future release.

Unexpected NullReferenceExceptions

Occasionally the Android Debug Log will mention NullReferenceExceptions that "cannot happen," or come from Mono for Android runtime code shortly before the app dies:

E/mono(15202): Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object
E/mono(15202):   at Java.Lang.Object.GetObject (IntPtr handle, System.Type type, Boolean owned)
E/mono(15202):   at Java.Lang.Object._GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):   at Java.Lang.Object.GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):   at Android.Views.View+IOnTouchListenerAdapter.n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_(IntPtr jnienv, IntPtr native__this, IntPtr native_v, IntPtr native_e)
E/mono(15202):   at (wrapper dynamic-method) object:b039cbb0-15e9-4f47-87ce-442060701362 (intptr,intptr,intptr,intptr)

or

E/mono    ( 4176): Unhandled Exception:
E/mono    ( 4176): System.NullReferenceException: Object reference not set to an instance of an object
E/mono    ( 4176): at Android.Runtime.JNIEnv.NewString (string)
E/mono    ( 4176): at Android.Util.Log.Info (string,string)

This can happen when the Android runtime decides to abort the process, which can happen for any number of reasons, including hitting the target's GREF limit or doing something "wrong" with JNI.

To see if this is the case, check the Android Debug Log for a message from your process similar to:

E/dalvikvm(  123): VM aborting

Abort due to Global Reference Exhaustion

The Android runtime's JNI layer only supports a limited number of JNI object references to be valid at any given point in time. When this limit is exceeded, things break.

The GREF (global reference) limit is 2000 references in the emulator, and ~52000 references on hardware.

You know you're starting to create too many GREFs when you see messages such as this in the Android Debug Log:

D/dalvikvm(  602): GREF has increased to 1801

When you reach the GREF limit, a message such as the following is printed:

D/dalvikvm(  602): GREF has increased to 2001
W/dalvikvm(  602): Last 10 entries in JNI global reference table:
W/dalvikvm(  602):  1991: 0x4057eff8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1992: 0x4057f010 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1993: 0x40698e70 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1994: 0x40698e88 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1995: 0x40698ea0 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1996: 0x406981f0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1997: 0x40698208 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1998: 0x40698220 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1999: 0x406956a8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  2000: 0x406956c0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602): JNI global reference table summary (2001 entries):
W/dalvikvm(  602):    51 of Ljava/lang/Class; 164B (41 unique)
W/dalvikvm(  602):    46 of Ljava/lang/Class; 188B (17 unique)
W/dalvikvm(  602):     6 of Ljava/lang/Class; 212B (6 unique)
W/dalvikvm(  602):    11 of Ljava/lang/Class; 236B (7 unique)
W/dalvikvm(  602):     3 of Ljava/lang/Class; 260B (3 unique)
W/dalvikvm(  602):     4 of Ljava/lang/Class; 284B (2 unique)
W/dalvikvm(  602):     8 of Ljava/lang/Class; 308B (6 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 316B
W/dalvikvm(  602):     4 of Ljava/lang/Class; 332B (3 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 356B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 380B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 428B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 452B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 476B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 500B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 548B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 572B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 596B (2 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 692B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 956B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1004B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1148B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 1172B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1316B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 3428B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 3452B
W/dalvikvm(  602):     1 of Ljava/lang/String; 28B
W/dalvikvm(  602):     2 of Ldalvik/system/VMRuntime; 12B (1 unique)
W/dalvikvm(  602):    10 of Ljava/lang/ref/WeakReference; 28B (10 unique)
W/dalvikvm(  602):     1 of Ldalvik/system/PathClassLoader; 44B
W/dalvikvm(  602):  1553 of Landroid/graphics/Point; 20B (1553 unique)
W/dalvikvm(  602):   261 of Landroid/graphics/Point; 28B (261 unique)
W/dalvikvm(  602):     1 of Landroid/view/MotionEvent; 100B
W/dalvikvm(  602):     1 of Landroid/app/ActivityThread$ApplicationThread; 28B
W/dalvikvm(  602):     1 of Landroid/content/ContentProvider$Transport; 28B
W/dalvikvm(  602):     1 of Landroid/view/Surface$CompatibleCanvas; 44B
W/dalvikvm(  602):     1 of Landroid/view/inputmethod/InputMethodManager$ControlledInputConnectionWrapper; 36B
W/dalvikvm(  602):     1 of Landroid/view/ViewRoot$1; 12B
W/dalvikvm(  602):     1 of Landroid/view/ViewRoot$W; 28B
W/dalvikvm(  602):     1 of Landroid/view/inputmethod/InputMethodManager$1; 28B
W/dalvikvm(  602):     1 of Landroid/view/accessibility/AccessibilityManager$1; 28B
W/dalvikvm(  602):     1 of Landroid/widget/LinearLayout$LayoutParams; 44B
W/dalvikvm(  602):     1 of Landroid/widget/LinearLayout; 332B
W/dalvikvm(  602):     2 of Lorg/apache/harmony/xnet/provider/jsse/TrustManagerImpl; 28B (1 unique)
W/dalvikvm(  602):     1 of Landroid/view/SurfaceView$MyWindow; 36B
W/dalvikvm(  602):     1 of Ltouchtest/RenderThread; 92B
W/dalvikvm(  602):     1 of Landroid/view/SurfaceView$3; 12B
W/dalvikvm(  602):     1 of Ltouchtest/DrawingView; 412B
W/dalvikvm(  602):     1 of Ltouchtest/Activity1; 180B
W/dalvikvm(  602): Memory held directly by tracked refs is 75624 bytes
E/dalvikvm(  602): Excessive JNI global references (2001)
E/dalvikvm(  602): VM aborting

In the above example (which, incidentally, comes from bug 685215) the problem is that too many Android.Graphics.Point instances are being created; see comment #2 for a list of fixes for this particular bug.

Typically, a useful solution is to find which type has too many instances allocated -- Android.Graphics.Point in the above dump -- then find where they're created in your source code and dispose of them appropriately (so that their Java-object lifetime is shortened). This is not always appropriate (#685215 is multithreaded, so the trivial solution avoids the Dispose call), but it's the first thing to consider.

You can enable GREF Logging to see when GREFs are created and how many exist.

Abort due to JNI type mismatch

If you hand-roll JNI code, it's possible that the types won't match correctly, e.g. if you try to invoke java.lang.Runnable.run on a type that doesn't implement java.lang.Runnable. When this occurs, there will be a message similar to this in the Android Debug Log:

W/dalvikvm( 123): JNI WARNING: can't call Ljava/Type;;.method on instance of Lanother/java/Type;
W/dalvikvm( 123):              in Lmono/java/lang/RunnableImplementor;.n_run:()V (CallVoidMethodA)
...
E/dalvikvm( 123): VM aborting

Dynamic Code Support

Dynamic code does not compile

To use C# dynamic in your application or library, you have to add System.Core.dll, Microsoft.CSharp.dll and Mono.CSharp.dll to your project.

In Release build, MissingMethodException occurs for dynamic code at run time.

  • It is likely that your application project does not have references to System.Core.dll, Microsoft.CSharp.dll or Mono.CSharp.dll. Make sure those assemblies are referenced.
    • Keep in mind that dynamic code always costs. If you need efficient code, consider not using dynamic code.
  • In the first preview, those assemblies were excluded unless types in each assembly are explicitly used by the application code. See the following for a workaround: http://lists.ximian.com/pipermail/mo...il/009798.html

Xamarin Workbook

If it's not already installed, install the Xamarin Workbooks app first. The workbook file should download automatically, but if it doesn't, just click to start the workbook download manually.