unoplatform/uno · error · InvalidOperationException

FoldableHingeAngleSensor must be initialized on the UI Threa

Error message

FoldableHingeAngleSensor must be initialized on the UI Thread

What it means

Thrown by FoldableHingeAngleSensor.GetHingeSensor when ContextHelper.Current is not an Activity. The sensor lookup requires an Activity context to obtain the SensorManager. If ContextHelper.Current is null or a non-Activity context (e.g. a Service or Application context), the cast fails and the error fires. The message attributes this to thread issues because ContextHelper.Current is typically only an Activity on the UI thread.

Source

Thrown at src/AddIns/Uno.UI.Foldable/FoldableHingeAngleSensor.Android.cs:60

		{
			get
			{
				return _hingeSensor != null;
			}
		}

		public FoldableHingeAngleSensor(object owner)
		{
			_hingeSensor = GetHingeSensor();
		}

		internal static bool HasHinge => GetHingeSensor() is not null;

		private static Sensor GetHingeSensor()
		{
			if (!(ContextHelper.Current is Activity currentActivity))
			{
				throw new InvalidOperationException("FoldableHingeAngleSensor must be initialized on the UI Thread");
			}

			_sensorManager ??= SensorManager.FromContext(currentActivity);

			if (_sensorManager is null)
			{
				return null;
			}

			var sensors = _sensorManager.GetSensorList(Android.Hardware.SensorType.All);

			return sensors.FirstOrDefault(s => s.Name.Contains(HINGE_SENSOR_NAME, StringComparison.OrdinalIgnoreCase)); // NAME - generic foldable device/s
		}

		public event EventHandler<NativeHingeAngleReading> ReadingChanged
		{
			add
			{

View on GitHub (pinned to 0418340488)

Solutions

  1. Ensure FoldableHingeAngleSensor (and HasHinge checks) run on the UI thread where ContextHelper.Current is guaranteed to be the Activity.
  2. Post the initialization to the UI thread: run on CoreDispatcher / Activity.RunOnUiThread before constructing the sensor.
  3. Delay sensor initialization until after the Activity's OnCreate/OnResume.

Example fix

// before: constructed off UI thread or before Activity ready
var sensor = new FoldableHingeAngleSensor(owner); // ContextHelper.Current not Activity → throws

// after: dispatch to UI thread
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    if (ContextHelper.Current is Android.App.Activity)
    {
        var sensor = new FoldableHingeAngleSensor(owner);
    }
});
Defensive patterns

Strategy: validation

Validate before calling

// Before constructing the sensor, verify we are on the UI thread with an Activity
if (ContextHelper.Current is Android.App.Activity activity)
{
    var sensor = new FoldableHingeAngleSensor(owner);
}

Try / catch

try {
    var sensor = new FoldableHingeAngleSensor(owner);
} catch (InvalidOperationException ex) when (ex.Message.Contains('UI Thread')) {
    // Re-dispatch to the UI thread and retry
}

Prevention

When it happens

Trigger: FoldableHingeAngleSensor is constructed or HasHinge is accessed when ContextHelper.Current is not an Activity — typically because initialization ran off the UI thread, before the Activity was created, or after it was destroyed (ContextHelper.Current set to a non-Activity).

Common situations: Initializing the hinge sensor from a background thread, a constructor that runs before the Activity is available, a background service context, or during app startup before ContextHelper.Current is populated.

Related errors


AI-assisted analysis of unoplatform/uno@0418340488 (2026-08-13). Data as JSON: /api/errors/da295aded0942c92. Report an issue: GitHub.