maui
maui copied to clipboard
[regression/8.0.0-preview.5.8529] Crash on scrolling collection view
Description
App just crashes with Java.Lang.RuntimeException: 'Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4b0165b'
Seems like the same issue as before. This should be solved here, but in every 8.0.* revision it seems to still be crashing (and I've tried them all).
Here is the call stack. It always seems to be the same. The very odd thing in it is the reference to net7.0/JniEnvironment.g.cs. As the version I'm runing the app is .net8 ¯_(ツ)_/¯
Steps to Reproduce
- open my repository in github (it has some redundant parts from testing over issues, but does the job)
- run on android emulator
- wait for a minute until it crashes (try to stay on the top of the page, so new images appear and push over images down)
Expected behavior: images open up and older images are pushed down
Actual behavior: images open up and older images are pushed down, but after about a minute you experience a crash with Java.Lang.RuntimeException: 'Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4b0165b
P.S. for anyone that might launch the app on windows and see the insane behavior of DataTemplates - I already reported it here, over a year back.
Link to public reproduction project repository
https://github.com/MissedSte4k/MAUI-Canvas-trying-to-use-a-recycled-bitmap-crash-sample
Version with bug
8.0.0-preview.5.8529
Is this a regression from previous behavior?
Yes, this used to work in .NET MAUI
Last version that worked well
8.0.0-preview.4.8333
Affected platforms
Android
Affected platform versions
No response
Did you find any workaround?
Nope. Tried everything referenced in issues that got solved in https://github.com/dotnet/maui/pull/12310, but to no avail.
Relevant log output
No response
Same here :/ I had to wait with releasing of my app due to huge issues in .net7 These were fixed in .net8 but now I am stopped at this one :/ so I cannot release my app to my customers again... No workaround works for me.
Verified this on Visual Studio Enterprise 17.9.0 Preview 1(8.0.3). Repro on Android 14.0-API34 and Windows 11, not repro on iOS 17.0 and MacCatalyst with below Project: TestImages.zip
@samhouts: what is the status on this issue? We experiencing the same crashes and this is preventing us releasing an urgent update to our customers!
Update after looking at similar issues and try/error: Workaround in https://github.com/dotnet/maui/issues/13534 did the job for me. Setting a fix height on an image in this case was not that what I wanted, but it prevents from crashes and unsatisfied customers.
Hope this helps solving this issue again! BR Stefan
Same here,
we get the same crashes in our public app right now with couple of devices. We have a simple screen to collect photos with the device camera and place this images into a horizontal scrolling collection view.
We see the same error as above:
Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(JniObjectReference , JniObjectReference , JniMethodInfo , JniArgumentValue* ) Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualBooleanMethod(String , IJavaPeerable , JniArgumentValue* ) Android.Views.ViewGroup.DrawChild(Canvas , View , Int64 ) Microsoft.Maui.Controls.Platform.Compatibility.ShellFlyoutRenderer.DrawChild(Canvas canvas, View child, Int64 drawingTime) Android.Views.ViewGroup.n_DrawChild_Landroid_graphics_Canvas_Landroid_view_View_J(IntPtr jnienv, IntPtr native__this, IntPtr native_canvas, IntPtr native_child, Int64 drawingTime) Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPLLJ_Z(_JniMarshal_PPLLJ_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, Int64 p2) com.microsoft.maui.PlatformContentViewGroup.dispatchDraw PlatformContentViewGroup.java:47 android.view.View.draw View.java:25151 androidx.recyclerview.widget.RecyclerView.drawChild RecyclerView.java:5499 android.view.ViewGroup.dispatchDraw ViewGroup.java:4534 androidx.recyclerview.widget.RecyclerView.draw RecyclerView.java:4898 android.view.View.updateDisplayListIfDirty View.java:24007 androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild CoordinatorLayout.java:1312 android.view.ViewGroup.dispatchDraw ViewGroup.java:4534 androidx.drawerlayout.widget.DrawerLayout.drawChild DrawerLayout.java:1483 crc640ec207abc449b2ca.ShellFlyoutRenderer.n_drawChild(Native Method) crc640ec207abc449b2ca.ShellFlyoutRenderer.drawChild ShellFlyoutRenderer.java:57 android.view.ViewGroup.dispatchDraw ViewGroup.java:4534
@mauiTeam Is there any update about this? I released now 5 Android updates the last 7 days with workarounds but i still see this crash happen in app center. Also in the crash report i have to information where this happens. Is there anything how i can find out more to see better error logs in AppCenter for Android?
Same issue with .NET 8. I have a CollectionView with images, if you scroll the list the app will crash. I didn't find any workaround.
When I replace the default StreamImageSourceService with the following code. Scroll through the CollectionView quickly and the program never crash again.
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.ConfigureImageSources(services =>
{
#if ANDROID
services.RemoveAll<IImageSourceService<IStreamImageSource>>();
services.RemoveAll<IImageSourceService<StreamImageSource>>();
services.AddService<IStreamImageSource>(_ => new CustomStreamImageSourceService());
services.AddService<StreamImageSource>(_ => new CustomStreamImageSourceService());
#endif
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
#if ANDROID
public class CustomStreamImageSourceService : StreamImageSourceService
{
public override async Task<IImageSourceServiceResult?> LoadDrawableAsync(IImageSource imageSource, ImageView imageView, CancellationToken cancellationToken = default)
{
var result = await base.GetDrawableAsync(imageSource, imageView.Context!, cancellationToken);
// if (result?.Value is BitmapDrawable drawable && drawable.Bitmap?.IsRecycled == true)
// {
// drawable.Bitmap.IsRecycled always false.
// }
imageView.SetImageDrawable(result?.Value);
return result;
}
}
#endif
}
It might be base.LoadDrawableAsync passes a recycled bitmap to imageView, causing the program to crash.
The same may be required for both FileImageSource and UriImageSource.
(Machine translation was used)
I'm getting this error when I have an Image on my CarouselView . This is a show stopper for me.
I'm using: Net 8 MAUI - Latest VS2022 == Version 17.9.5
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.14" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.14" />
I have the same issue with the latest VS version and .NET 8.
I'm receiving the images through an API call from a FileManager, and the image is located inside grid, it crashed the app very rarely.
I can offer more info if needed.
Chiming in here with my 2c worth of evidence. I'm getting same issue with dotnet 8.0 (8.0.3) and VS 2022 Version 17.9.5 (Android app)
2024-04-10 09:35:54.868 +08:00 [FTL] Java.Lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@fe28425
at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args)
at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualBooleanMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
at Android.Views.ViewGroup.DrawChild(Canvas canvas, View child, Int64 drawingTime)
at Microsoft.Maui.Controls.Platform.Compatibility.ShellFlyoutRenderer.DrawChild(Canvas canvas, View child, Int64 drawingTime)
at Android.Views.ViewGroup.n_DrawChild_Landroid_graphics_Canvas_Landroid_view_View_J(IntPtr jnienv, IntPtr native__this, IntPtr native_canvas, IntPtr native_child, Int64 drawingTime)
at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPLLJ_Z(_JniMarshal_PPLLJ_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, Int64 p2)
I'm rather glad I found my way to this issue, I thought I was doing something wrong.
Confirmed that this regressed between 8.0.0-preview.4.8333 and 8.0.0-preview.5.8529. Before pre5, the scrolling performance was atrocious, so I assume this was a memory leak resolved by properly disposing of the images. However, that leads to this crash.
Not sure exactly what the culprit was, but https://github.com/dotnet/maui/pull/14933, https://github.com/dotnet/maui/pull/12011, and https://github.com/dotnet/maui/pull/14109 seem most sus.
Incidentally, I changed the Frame to a Border to see if it helped and with that, I see that the background color of the cell goes from white in pre4 to black in pre5, which seems to be related to https://github.com/dotnet/maui/pull/14933 and is probably another regression/behavior change.
Oh, yep, the repro is using a DTS, so looks like https://github.com/dotnet/maui/pull/12011 is most likely. @Redth fyi
I have seen this before. Not specifying the Height and Width request, in your ImageViews, (using URLs of uploaded pictures with 1000x1600 for example as source) that are contained in your CollectionView, lead to the following problems:
In Android: You get random runtime crashes, when you scroll down the collection view. In IOS: You get empty collection view the first time you enter the page. Collection view with only first item loaded the second time you enter the page. And full collection view when you enter 3rd time in the page.
Setting WidthRequest=100, HeightRequest=100 is quick way to check if this applies to you.
(Forgot to say that this IOS behavior does not repeat when you close and open the app (it seems caching is involved in making the problem resolve itself), only reinstall introduces it again. But on Android it is persistent.)
Thanks for the reply!
Setting WidthRequest=100, HeightRequest=100 is quick way to check if this applies to you.
Meaning the crashing stops? I've wondered if perhaps I can set or bind the height/width request to a calculated value so it is provided (but still fills the available width/height but stops the crashes)
Meaning the crashing stops? I've wondered if perhaps I can set or bind the height/width request to a calculated value so it is provided (but still fills the available width/height but stops the crashes)
Not only the android crashing. The weird behavior on IOS also. You open "details" page, that contains CollectionView, that has ItemTeplate of DataTemplate of Image. Nothing else. And on the Image you have set "MaximumWidthRequest" and "MaximumHeightRequest", with aspect set to Fit. Open details once - empty. Second - only one image showing. Third time - everything.
Set specific measurements and both problems are gone.
To make matter worse - on the device I develop with most of the time, this problem could not be reproduced. On one of the test devices, this problem was showing, but only if your list has set amount of items. 4 or 5 pages - no problem. And the key to find this out was another test device, that was throwing this exception (crashing, actually), the second you try to scroll.
I hope this saves you some time.
Any news on this? This issue is still presenting with maui 8.0.40. I'm not using an itemTemplateSelector in my case, just a collectionview where every item of the list is a grid with an image and labels. Set fixed Width and Height is not working
When I replace the default
StreamImageSourceServicewith the following code. Scroll through the CollectionView quickly and the program never crash again.public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }) .ConfigureImageSources(services => { #if ANDROID services.RemoveAll<IImageSourceService<IStreamImageSource>>(); services.RemoveAll<IImageSourceService<StreamImageSource>>(); services.AddService<IStreamImageSource>(_ => new CustomStreamImageSourceService()); services.AddService<StreamImageSource>(_ => new CustomStreamImageSourceService()); #endif }); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } #if ANDROID public class CustomStreamImageSourceService : StreamImageSourceService { public override async Task<IImageSourceServiceResult?> LoadDrawableAsync(IImageSource imageSource, ImageView imageView, CancellationToken cancellationToken = default) { var result = await base.GetDrawableAsync(imageSource, imageView.Context!, cancellationToken); // if (result?.Value is BitmapDrawable drawable && drawable.Bitmap?.IsRecycled == true) // { // drawable.Bitmap.IsRecycled always false. // } imageView.SetImageDrawable(result?.Value); return result; } } #endif }It might be
base.LoadDrawableAsyncpasses a recycled bitmap toimageView, causing the program to crash. The same may be required for bothFileImageSourceandUriImageSource. (Machine translation was used)
From my tests this resolve the problem
I ran into this one again on my own app when I decided to remove the WidthRequest from my images. Setting an explicit WidthRequest and HeightRequest is certainly the workaround.
@samhouts I've observed that WidthRequest technique works only under certain circumstances. I create a sample app to repro the issue.
App has a simple timer that periodically updates Image.Source. On my real devices (Galaxy A52s, Galaxy S22), it crashes with an update period of 70ms. There are 2 buttons to increase/decrease the delay.
Interestingly, if Image.WidthRequest is 500, then it crashes. If I change WidthRequest to 400 or lower, then it doesn't crash.
@viktorszekeress Did you try if this workaround work for you?
For me it seems to work
When I replace the default
StreamImageSourceServicewith the following code. Scroll through the CollectionView quickly and the program never crash again.public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }) .ConfigureImageSources(services => { #if ANDROID services.RemoveAll<IImageSourceService<IStreamImageSource>>(); services.RemoveAll<IImageSourceService<StreamImageSource>>(); services.AddService<IStreamImageSource>(_ => new CustomStreamImageSourceService()); services.AddService<StreamImageSource>(_ => new CustomStreamImageSourceService()); #endif }); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } #if ANDROID public class CustomStreamImageSourceService : StreamImageSourceService { public override async Task<IImageSourceServiceResult?> LoadDrawableAsync(IImageSource imageSource, ImageView imageView, CancellationToken cancellationToken = default) { var result = await base.GetDrawableAsync(imageSource, imageView.Context!, cancellationToken); // if (result?.Value is BitmapDrawable drawable && drawable.Bitmap?.IsRecycled == true) // { // drawable.Bitmap.IsRecycled always false. // } imageView.SetImageDrawable(result?.Value); return result; } } #endif }It might be
base.LoadDrawableAsyncpasses a recycled bitmap toimageView, causing the program to crash. The same may be required for bothFileImageSourceandUriImageSource. (Machine translation was used)
@Simoo23 I tried that and it does indeed solve the original problem - application doesn't crash now. The new problem is that RAM usage skyrockets for me to 2+GB. I have a CollectionView with potentially 200+ images (loaded on demand).
I also noticed decreased performance with this solution.
What I eventually did is that instead of converting byte[] to ImageSource I convert byte[] to Image - meaning it creates whole new Image for each byte[]. This does also increase RAM usage a bit (100 MB), but from my testing it settles down after a while and seems to behave stable.
@viktorszekeress I'll try to check the Ram usage too.
But how do you convert byte[] to Image and bind to Image component in MVVM without using ImageSource?
@Simoo23 Instead of using Image in XAML and binding ImageSource, I use ContentView and I bind Content to byte[].
@Simoo23 Instead of using
Imagein XAML and bindingImageSource, I useContentViewand I bindContenttobyte[].
Does this work flawlessly on both iOS and ANdroid?
Also, what if we need to bind the image from an HTTP URI link? Any ideas there?
Does this work flawlessly on both iOS and ANdroid?
I haven't tested it on iOS. The question is, do we need this workaround there?
Also, what if we need to bind the image from an HTTP URI link? Any ideas there?
It's just a matter of converter (parameter) and how you construct the image.
Is not possibile to increase the priority of this bug? I think that this is a basic feature as we are talking of a simple list of images and this bug is opened from Nov 17, 2023. We have some workarounds but they all have problems
Interestingly, if
Image.WidthRequestis 500, then it crashes. If I changeWidthRequestto 400 or lower, then it doesn't crash.
Are you sure about this? I cannot say about "width", but I am using "HeightRequest" of 500 and above, without this issue manifesting.
Are you sure about this? I cannot say about "width", but I am using "HeightRequest" of 500 and above, without this issue manifesting.
I'm sure. Obviously, it depends on other circumstances, like: original size of the image, aspect ratio, available area... Just try out the sample I provided.