Select to view content in your preferred language

[Android] ObjectDisposedException in AndroidCompassProvider tearing down MAUI app

442
5
06-07-2026 07:29 AM
Labels (2)
esp1rl
by
Occasional Contributor

EDIT: not all Android users experience it, and it doesn't happen on every startup, it occurs once in a while

Hi, this exception is from a MAUI 10.0.70 app using ArcGIS Maps SDK 300.0.0.

Many of our Android users experience this one, and it happens at app startup. Well before any IWindowManagerInvoker is expected to be disposed of.

The app initializes MapView.LocationDisplay on startup with default data source. Initialization happens at MapView.Loaded event.

android.runtime.JavaProxyThrowable: [System.ObjectDisposedException]: Cannot access disposed object with JniIdentityHashCode=48158090.
Object name: 'Android.Views.IWindowManagerInvoker'.
	at Android.Views.IWindowManagerInvoker.get_DefaultDisplay + 0x0(Unknown Source)
	at Esri.ArcGISRuntime.Location.AndroidCompassProvider.Android.Hardware.ISensorEventListener.OnSensorChanged + 0x0(Unknown Source)
	at Android.Hardware.ISensorEventListenerInvoker.n_OnSensorChanged_Landroid_hardware_SensorEvent_ + 0x0(Unknown Source)
	at crc64f261feee1d215ead.AndroidCompassProvider.n_onSensorChanged(Native Method)
	at crc64f261feee1d215ead.AndroidCompassProvider.onSensorChanged(AndroidCompassProvider.java:37)
	at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:1203)
	at android.os.MessageQueue.nativePollOnce(Native Method)
	at android.os.MessageQueue.nextLegacy(MessageQueue.java:985)
	at android.os.MessageQueue.next(MessageQueue.java:1094)
	at android.os.Looper.loopOnce(Looper.java:222)
	at android.os.Looper.loop(Looper.java:392)
	at android.app.ActivityThread.main(ActivityThread.java:10346)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:638)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:972)

 
PS: Would it be an idea to wrap the compass provider code (and similar code) in try/catch to avoid tearing down the whole app? Or perhaps route the exception through a mechanism akin to TaskScheduler.UnobservedTaskException and possibility to use SetObserved().

5 Replies
GKmieliauskas
Esri Regular Contributor

Hi,

Our app initializes MapView.LocationDisplay with default data source on OnPageLoaded event. It works without issues.

0 Kudos
esp1rl
by
Occasional Contributor

This error may trigger due to the lifecycle of the app, in case of pause/resume. Claude suggest that the IWindowManagerInvoker may be cached in a .NET class field, and become garbage collected on the Java side while on the .NET side an active reference is kept, to what is then a disposed object. That could explain the JNI details in the exception. Other reasons could be improper usage of JavaCast.

Claude also identified the Android WindowManager getDefaultDisplay to be a deprecated API at Android API level 30 / Android 11 (September 2020). Please see WindowManager  |  API reference  |  Android Developers

0 Kudos
esp1rl
by
Occasional Contributor

Summary

SystemLocationDataSource on Android can malfunction because its internal AndroidCompassProvider obtains an IWindowManager from the Android application context instead of an activity context. The application context is not guaranteed to be associated with a window, so the display properties retrieved from it may not reflect the actual display/rotation of the visible activity, leading to incorrect compass alignment and/or crashes due to disposed object.

Internal anatomy (relevant private structure)

 
SystemLocationDataSource
└── AndroidCompassProvider (private field)
└── IWindowManager (private field)

The IWindowManager instance is used to query device display properties, which are then used to align the compass direction.

Root cause

The IWindowManager is created from the Android application context. Because the application context is not guaranteed to be tied to a window, the display information it returns can be wrong. The instance should instead be created from an activity context, which is associated with an actual window and display.

Workaround

  1. Create a new IWindowManager instance from the correct activity context.
  2. Use reflection to replace the private IWindowManager field inside the private AndroidCompassProvider field of SystemLocationDataSource.

Timing is critical: the replacement must be performed after SystemLocationDataSource.StartAsync() completes, because StartAsync() instantiates a new AndroidCompassProvider. The provider is set to null on StopAsync(), so the workaround must be re-applied after every restart.

Suggested fix

Note that IWindowManager.getDisplay() is deprecated precisely because of this class of problem. The recommended approach is to migrate to the newer display APIs rather than continuing to rely on the deprecated call.

0 Kudos
esp1rl
by
Occasional Contributor

Hi @GKmieliauskas The above workaround solves the problem for our MAUI application. Verified by Sentry monitoring.

Also, ESRI support case #04216208 has been registered on this issue.

0 Kudos
esp1rl
by
Occasional Contributor

esp1rl_0-1783676185821.png

 

0 Kudos