#38620·maui

[Android] Material 3 - TrySetAppBarLiftTargetIfOnScreen might throw java.lang.NullPointerException

Author: EmilienDupCreated Sep 17, 2026Updated Sep 17, 2026
Labelst/bugplatform/androids/verifieds/triagedi/regressionmaterial3regressed-in-10.0.90

Description

Microsoft.Maui.Platform.AppbarLayoutExtensions.TrySetAppBarLiftTargetIfOnScreen (added in #35181, "[Android] Fix AppBar flicker on CheckBox/Switch toggle with Material 3") crashes the app with a java.lang.NullPointerException when the Runnable it schedules via MauiScrollView.PostTrySetAppBarLiftTargetIfOnScreen fires while the app is under GC pressure and the scroll view hierarchy is churning (CarouselView page swipes, CollectionView/ItemsSource resets, rapid navigation).

The crash is:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Rect.set(int, int, int, int)' on a null object reference
    at android.view.View.getGlobalVisibleRect(View.java:...)
    at android.view.View.getGlobalVisibleRect(View.java:...)
    at mono.java.lang.Runnable.n_run(Native Method)
    at mono.java.lang.Runnable.run(Runnable.java:29)
    ...

with the managed side pointing exactly at:

Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(...)
Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualBooleanMethod(...)
Android.Views.View.GetGlobalVisibleRect(Rect r)
Microsoft.Maui.Platform.AppbarLayoutExtensions.TrySetAppBarLiftTargetIfOnScreen(View view)
Microsoft.Maui.Platform.MauiScrollView.<GetOrCreateSetAppBarLiftTargetRunnable>b__39_0()
Java.Lang.Runnable.Run()
Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)

This matches our original field report byte-for-byte, including the IRunnableInvoker.n_Run frame naming. Building the same repro with PDB-symbolicated line numbers against current main source resolves that TrySetAppBarLiftTargetIfOnScreen frame to AppbarLayoutExtensions.cs:56:

csharp
if (view.GetGlobalVisibleRect(state.VisibleRect))

state.VisibleRect is a readonly Rect field allocated once per view (cached in a ConditionalWeakTable<View, AppBarLiftState>) and reused across calls. The NPE's own message — Rect.set(...) on a null object reference — means the argument passed to getGlobalVisibleRect resolved to a null JNI reference on the Java side, even though state.VisibleRect is a live, non-null managed object and is never explicitly disposed anywhere in this code path. This points at the cached Rect's Java peer being invalidated/collected out from under the managed reference (a Java.Interop GC-bridge race), rather than a plain "view already detached" case — the method already guards against that with view.IsAlive() && view.IsAttachedToWindow && view.Visibility == Visible before ever touching the Rect, and those guards are passing right up until the crash.

This is fully reproducible (not a one-off field report) — see attached repro project and logs below.

Steps to Reproduce

  1. Create/open a .NET MAUI Android app with <UseMaterial3>true</UseMaterial3> set in the csproj (this is what turns on RuntimeFeature.IsMaterial3Enabled, which gates the code path).
  2. Host a ScrollView (directly, or via CarouselView/CollectionView item templates) under a Shell or NavigationPage AppBar.
  3. Churn the scroll view hierarchy quickly — e.g. repeatedly jump a CarouselView.Position to random indices and periodically replace its ItemsSource wholesale — while the app is under GC pressure.

A minimal repro project that does exactly this is attached (AppBarLiftCrashRepro, see the accompanying zip / repo folder). It starts its stress loop automatically as soon as the page appears — no manual interaction needed. On both devices we tested, it crashes within 5-30 seconds:

  • sdk_gphone64_arm64 emulator, Android 16 (API 36)
  • Pixel 9a, Android 17 (API 37)

Full logcat crash excerpts for both are included as crash-logs/*.log in the repro project.

Expected Behavior

The AppBar lift-on-scroll target update is a cosmetic, best-effort UI enhancement (elevation/shadow on the toolbar) and should never be able to crash the app, regardless of how quickly the scroll view hierarchy is churning or GC timing lines up.

Actual Behavior

App crashes with the NullPointerException above.

Basic Information

  • .NET MAUI version: Microsoft.Maui.Controls 10.0.101 — matches exactly what our production app is pinned to.
  • Also confirmed present (via source inspection) on the current main branch, resolving to Microsoft.Maui.Controls 11.0.0-rc.1.26451.6 — the file AppbarLayoutExtensions.cs was added whole-cloth by #35181 and has had no further commits since, so the same unguarded Rect reuse exists there too.
  • Affected platform: Android only (the feature is Android-specific)
  • IDE: N/A — reproduced via dotnet build -t:Run

Environment

Emulator:

Device: sdk_gphone64_arm64 (emulator-5554)
Android: 16 (API 36)
ABI: arm64-v8a

Physical device:

Device: Pixel 9a
Android: 17 (API 37)

Repro project TargetFramework: net10.0-android MauiVersion: 10.0.101 SDK used: 10.0.300 (maui-android workload 10.0.20) Feature switch under test: <UseMaterial3>true</UseMaterial3>

Link to public reproduction project repository

https://github.com/EmilienDup/MAUIAndroidAppBarLiftTargetNullPointerException

Version with bug

10.0.101

Is this a regression from previous behavior?

No, this is something new

Last version that worked well

No response

Affected platforms

Android

Affected platform versions

No response

Did you find any workaround?

No response

Relevant log output

bash
Emulator (`crash-logs/emulator-android16-api36.log`):


09-17 11:29:04.375 23785 23785 E AndroidRuntime: FATAL EXCEPTION: main
09-17 11:29:04.375 23785 23785 E AndroidRuntime: Process: com.companyname.appbarliftcrashrepro, PID: 23785
09-17 11:29:04.375 23785 23785 E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Rect.set(int, int, int, int)' on a null object reference
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.view.View.getGlobalVisibleRect(View.java:20764)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.view.View.getGlobalVisibleRect(View.java:20788)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at mono.java.lang.Runnable.n_run(Native Method)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at mono.java.lang.Runnable.run(Runnable.java:29)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.os.Handler.handleCallback(Handler.java:1070)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:125)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.os.Looper.dispatchMessage(Looper.java:333)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.os.Looper.loopOnce(Looper.java:263)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:367)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:9282)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:566)
09-17 11:29:04.375 23785 23785 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:929)
09-17 11:29:04.378 23785 23785 I MonoDroid: Java.Lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Rect.set(int, int, int, int)' on a null object reference
09-17 11:29:04.378 23785 23785 I MonoDroid:    at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args)
09-17 11:29:04.378 23785 23785 I MonoDroid:    at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualBooleanMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
09-17 11:29:04.378 23785 23785 I MonoDroid:    at Android.Views.View.GetGlobalVisibleRect(Rect r)
09-17 11:29:04.378 23785 23785 I MonoDroid:    at Microsoft.Maui.Platform.AppbarLayoutExtensions.TrySetAppBarLiftTargetIfOnScreen(View view)
09-17 11:29:04.378 23785 23785 I MonoDroid:    at Microsoft.Maui.Platform.MauiScrollView.<GetOrCreateSetAppBarLiftTargetRunnable>b__39_0()
09-17 11:29:04.378 23785 23785 I MonoDroid:    at Java.Lang.Runnable.Run()
09-17 11:29:04.378 23785 23785 I MonoDroid:    at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
09-17 11:29:04.378 23785 23785 I MonoDroid:   --- End of managed Java.Lang.NullPointerException stack trace ---


Physical Pixel 9a (`crash-logs/pixel9a-android17-api37.log`):


09-17 11:30:26.515 22887 22887 E AndroidRuntime: FATAL EXCEPTION: main
09-17 11:30:26.515 22887 22887 E AndroidRuntime: Process: com.companyname.appbarliftcrashrepro, PID: 22887
09-17 11:30:26.515 22887 22887 E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Rect.set(int, int, int, int)' on a null object reference
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.view.View.getGlobalVisibleRect(View.java:20946)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.view.View.getGlobalVisibleRect(View.java:20970)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at mono.java.lang.Runnable.n_run(Native Method)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at mono.java.lang.Runnable.run(Runnable.java:29)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.os.Handler.handleCallback(Handler.java:1095)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.os.Handler.dispatchMessageImpl(Handler.java:135)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:125)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.os.Looper.loopOnce(Looper.java:296)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:397)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:9523)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:575)
09-17 11:30:26.515 22887 22887 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:939)
09-17 11:30:26.535 22887 22887 I MonoDroid: Java.Lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Rect.set(int, int, int, int)' on a null object reference
09-17 11:30:26.535 22887 22887 I MonoDroid:    at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args)
09-17 11:30:26.535 22887 22887 I MonoDroid:    at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualBooleanMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
09-17 11:30:26.535 22887 22887 I MonoDroid:    at Android.Views.View.GetGlobalVisibleRect(Rect r)
09-17 11:30:26.535 22887 22887 I MonoDroid:    at Microsoft.Maui.Platform.AppbarLayoutExtensions.TrySetAppBarLiftTargetIfOnScreen(View view)
09-17 11:30:26.535 22887 22887 I MonoDroid:    at Microsoft.Maui.Platform.MauiScrollView.<GetOrCreateSetAppBarLiftTargetRunnable>b__39_0()
09-17 11:30:26.535 22887 22887 I MonoDroid:    at Java.Lang.Runnable.Run()
09-17 11:30:26.535 22887 22887 I MonoDroid:    at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
09-17 11:30:26.535 22887 22887 I MonoDroid:   --- End of managed Java.Lang.NullPointerException stack trace ---