-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Android] Fix app crash caused by dynamic template switching in ListView #24808
base: main
Are you sure you want to change the base?
Conversation
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you re-enable this device test for android?
@PureWeen, I have modified changes. Could you please validate it once and let me know if there are any further concerns. |
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the test is failing
09-23 03:31:56.106 4471 4471 E AndroidRuntime: FATAL EXCEPTION: main
09-23 03:31:56.106 4471 4471 E AndroidRuntime: Process: com.microsoft.maui.controls.devicetests, PID: 4471
09-23 03:31:56.106 4471 4471 E AndroidRuntime: android.runtime.JavaProxyThrowable: [System.NullReferenceException]: Object reference not set to an instance of an object.
09-23 03:31:56.106 4471 4471 E AndroidRuntime: at Microsoft.Maui.Graphics.Platform.GraphicsExtensions.AsColor(Unknown Source:0)
09-23 03:31:56.106 4471 4471 E AndroidRuntime: at Microsoft.Maui.Platform.ColorExtensions.ToPlatform(Unknown Source:0)
09-23 03:31:56.106 4471 4471 E AndroidRuntime: at Microsoft.Maui.Platform.ColorExtensions.ToPlatform(Unknown Source:0)
09-23 03:31:56.106 4471 4471 E AndroidRuntime: at Microsoft.Maui.Controls.Handlers.Compatibility.ListViewAdapter.UpdateSeparatorColor(Unknown Source:0)
09-23 03:31:56.106 4471 4471 E AndroidRuntime: at Microsoft.Maui.Controls.Handlers.Compatibility.ListViewAdapter.GetView(Unknown Source:0)
09-23 03:31:56.106 4471 4471 E AndroidRuntime: at Microsoft.Maui.Controls.Handlers.Compatibility.ListViewRenderer.GetDesiredSize(Unknown Source:0)
09-23 03:31:56.106 4471 4471 E AndroidRuntime: at Microsoft.Maui.Controls.Handlers.Compatibility.VisualElementRenderer`1[[Microsoft.Maui.Controls.ListView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral,
Azure Pipelines successfully started running 3 pipeline(s). |
/rebase |
09f3833
to
aec2b55
Compare
Azure Pipelines successfully started running 3 pipeline(s). |
/rebase |
aec2b55
to
07f8c3b
Compare
Azure Pipelines successfully started running 3 pipeline(s). |
|
||
if (platformView.Parent != null && platformView.Parent is ViewGroup parentViewGroup) | ||
{ | ||
parentViewGroup.RemoveView(platformView); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RemoveFromParent
extension method can be used here.
platformView.RemoveFromParent();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jsuarezruiz, Thank you for your suggestion regarding the use of the RemoveFromParent
extension method. I implemented this fix; however, the device test case is still experiencing app crashes.
Upon further investigation, we discovered that the crash occurs during the execution of the ChangingTemplateTypeDoesNotCrash
test case. The issue arises because grouping is enabled, but the data provided is not in a grouped format, leading to the app crashing when running the command-line device test case.
We validated this by running a standalone sample with the fix applied, and the same test case also passed without any issues when checked manually. The crashes seem to only occur during command-line execution.
We are currently delving deeper into this issue and would greatly appreciate any insights you may have.
@PureWeen, The test failure is caused by the |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
/rebase |
c55e1fc
to
403de20
Compare
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
@@ -244,6 +244,12 @@ public void Update(ViewCell cell) | |||
|
|||
var platformView = _viewCell.View.ToPlatform(Element.FindMauiContext()); | |||
_viewHandler = (IPlatformViewHandler)_viewCell.View.Handler; | |||
|
|||
if (platformView?.Parent is ViewGroup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're using RemoveFromParent
I don't think you need the if statement here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PureWeen, I have modified the code based on your concerns, could you please validate once and let me know if there are any concerns.
…n RemoveFromParent().
Azure Pipelines successfully started running 3 pipeline(s). |
return null; | ||
return Current?.Windows?.Count > 0 | ||
? Current.Windows[0].MauiContext.Context?.GetAccentColor() | ||
: Color.FromRgba(50, 79, 133, 255); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this color based on?
Can the code that's calling this be fixed to handle a null value better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PureWeen , I've updated the code to handle null values more effectively. Specifically, we are now using a default fallback color of "#ff33b5e5"
when both the current accent color and the passed defaultColor
are null. This fallback color is based on the reference code from the GetAccentColor
method in ContextExtensions.cs
here, ensuring consistency with the default Android accent color in working scenarios.
Could you please review and let me know if there are any further concerns?
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
@@ -17,7 +17,7 @@ public static AColor ToPlatform(this Color self, int defaultColorResourceId, Con | |||
=> self?.ToPlatform() ?? new AColor(ContextCompat.GetColor(context, defaultColorResourceId)); | |||
|
|||
public static AColor ToPlatform(this Color? self, Color defaultColor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, the separator line must use the color from the SeparatorColor property, but if it is not set and is null, a color from an Android Resource such as global::Android.Resource.Attribute.ColorAccent
should be used. So, we need to identify why the AccentColor is null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jfversluis, Thank you for the feedback! I've updated the code to address the potential null values effectively and to avoid unintended defaulting to #ff33b5e5
across views. Specifically, I’ve ensured that the color retrieval method now uses the primary context when available via Current.Windows[0].MauiContext.Context
, and if not, it falls back to Current?.FindMauiContext()?.Context
(During device tests).
Please review and let us know if any further changes are required.
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
return Current.Windows[0].MauiContext.Context?.GetAccentColor(); | ||
var context = Current?.Windows?.Count > 0 ? Current.Windows[0].MauiContext.Context : Current?.FindMauiContext()?.Context; | ||
if (context is not null) | ||
return context?.GetAccentColor(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the current Window MauiContext is null, we keep having the same null Color exception, right?
We could fallback to Application.Current.FindMauiContext()
in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jsuarezruiz , Thank you for the feedback. I’ve added a fallback to ensure context is retrieved effectively in all cases, even when the primary window context might not be accessible.
Please review and let us know if any further changes are required.
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
/rebase |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
Exception I – Object reference not set to an instance of an object at GraphicsExtensions.AsColor :
During the execution of the device test case -
ChangingTemplateTypeDoesNotCrash
, a fatal exception was thrown, causing a crash.Root Cause
The root cause of the
NullReferenceException
was identified as a failure to check for a valid context or color before calling the AsColor method. Specifically, the line of code responsible for this was:In the
UpdateSeparatorColor
method, when returning null forApplication.AccentColor
, the method requests:bline.SetBackgroundColor(separatorColor.ToPlatform(Application.AccentColor));
Since no default separator color was set, this led to the issue. The failure was particularly observed in our test case that enabled grouping, which is why only theChangingTemplateTypeDoesNotCrash
test case was failing.Description of Change
To resolve this issue, the following modifications were implemented in the relevant code segment:
Default Color Implementation: A fallback mechanism was implemented to provide a default color (e.g.,
Color.FromRgba(50, 79, 133, 255))
when thewindow.count
resource is unavailable. This approach prevents the application from crashing and ensures that the UI continues to function smoothly even in command line device test cases.Exception II – The specified child already has a parent. you must call
removeView()
on the child’s parent first atViewGroup.addViewInner
.Root cause
In the ViewCellRenderer class, the platform view was being recreated for each cell without properly removing the existing parent view (i.e., the ViewCellContainer ) before attempting to add the new view. This caused an exception:'The specified child already has a parent. You must call removeView() on the child's parent first. 'The issue arose due to improper handling of the platform view's parent when switching between different DataTemplates in a ListView using the RetainElement caching strategy in .NET MAUI.
Description of Issue Fix
The fix involved checking if the platformView already had a parent (i.e., ViewGroup) and ensuring that the parent was removed before adding the platformView to the new container. By introducing this conditional check, the system prevents the platform view from being associated with multiple parents, which caused the "The specified child already has a parent" exception. This change ensures that dynamic template changes in the ListView are handled correctly, improving view recycling and maintaining stable rendering without conflicts.
Tested the behavior in the following platforms.
Issues Fixed
Fixes #24701
Output
Before fix:
After fix:
Testcase:
The Testcase is already available for this fix. Please refer to the PR link below for reference.
Clear out prototype cell when changing ItemSource by PureWeen · Pull Request #24700 · dotnet/maui (github.com)