Skip to content
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

Remove Bindings on Popup Close #1614

Merged
merged 8 commits into from
Feb 17, 2024
Merged

Conversation

cat0363
Copy link
Contributor

@cat0363 cat0363 commented Dec 20, 2023

In this PR, we will correct it so that SetColor of a Popup that has already been destroyed is not called.

Description of Change

If the SetColor method is called after closing the Popup, an exception will occur at the following location.

[src\CommunityToolkit.Maui.Core\Views\Popup\PopupExtensions.android.cs]

public static void SetColor(this Dialog dialog, in IPopup popup)
{
    if (popup.Color is null)
    {
        return;
    }

    var window = GetWindow(dialog);    // <- here
    window.SetBackgroundDrawable(new ColorDrawable(popup.Color.ToPlatform(AColorRes.BackgroundLight, dialog.Context)));
}

Add a guard condition to the call to the SetColor method.

[src\CommunityToolkit.Maui.Core\Handlers\Popup\PopUpHandler.android.cs]

public static void MapColor(PopupHandler handler, IPopup view)
{
    if (!handler.PlatformView.IsDisposed())
    {
        handler.PlatformView.SetColor(view);
    }
}

Similarly, add guard conditions to calls to the SetAnchor and SetSize methods.

public static void MapAnchor(PopupHandler handler, IPopup view)
{
    if (!handler.PlatformView.IsDisposed())
    {
        handler.PlatformView.SetAnchor(view);
    }
}

public static void MapSize(PopupHandler handler, IPopup view)
{
    ArgumentNullException.ThrowIfNull(handler.Container);

    if (!handler.PlatformView.IsDisposed())
    {
        handler.PlatformView.SetSize(view, handler.Container);
        handler.PlatformView.SetAnchor(view);
    }
}

void OnLayoutChange(object? sender, EventArgs e)
{
    if (VirtualView?.Handler?.PlatformView is Dialog dialog && Container is not null)
    {
        if (!dialog.IsDisposed())
        {
            PopupExtensions.SetSize(dialog, VirtualView, Container);
        }
    }
}

Linked Issues

PR Checklist

  • Has a linked Issue, and the Issue has been approved(bug) or Championed (feature/proposal)
  • Has tests (if omitted, state reason in description)
  • Has samples (if omitted, state reason in description)
  • Rebased on top of main at time of PR
  • Changes adhere to coding standard
  • Documentation created or updated: https://github.com/MicrosoftDocs/CommunityToolkit/pulls

Additional information

Below is the verification video.

Android.Emulator.-.pixel_2_-_api_30_5554.2023-12-20.15-32-08.mp4

Even if I change the AppTheme, I can see that it is working as intended without any crashes.

@cat0363 cat0363 changed the title Add disposed check on Android Add Popup disposed check on Android Dec 20, 2023
@pictos
Copy link
Member

pictos commented Jan 18, 2024

Hey @cat0363, thanks for PR... For me, this looks more like a workaround than an actual fix. We dispose of the PlatformView when the DisconnectHandler is called, so the Map methods shouldn't trigger anymore, for that specific instance. So I believe the error is elsewhere. I suggest we check if there's another path to PlatformView.Dispose first, then start working from there

@cat0363
Copy link
Contributor Author

cat0363 commented Jan 18, 2024

@pictos , Thank you for your comment.
I will reconsider. I would like to try to find the root cause of the problem.

@cat0363
Copy link
Contributor Author

cat0363 commented Jan 19, 2024

The root cause of this problem is that the Binding is not released after the Popup is closed.
Because the Binding was not released, the MapColor method was called via the Color property when the theme was changed after the Popup was closed.

Revert the modifications you made previously and make the following changes.

[src\CommunityToolkit.Maui\Views\Popup\Popup.shared.cs]

protected virtual async Task OnClosed(object? result, bool wasDismissedByTappingOutsideOfPopup, CancellationToken token = default)
{
	((IPopup)this).OnClosed(result);
	((IResourceDictionary)resources).ValuesChanged -= OnResourcesChanged;

	RemoveBinding(Popup.ContentProperty);
	RemoveBinding(Popup.ColorProperty);
	RemoveBinding(Popup.SizeProperty);
	RemoveBinding(Popup.CanBeDismissedByTappingOutsideOfPopupProperty);
	RemoveBinding(Popup.VerticalOptionsProperty);
	RemoveBinding(Popup.HorizontalOptionsProperty);
	RemoveBinding(Popup.StyleProperty);

	await popupDismissedTaskCompletionSource.Task.WaitAsync(token);
	Parent = null;

	dismissWeakEventManager.HandleEvent(this, new PopupClosedEventArgs(result, wasDismissedByTappingOutsideOfPopup), nameof(Closed));
}

Below is the verification video.

Android.Emulator.-.pixel_2_-_api_30_5554.2024-01-19.11-42-36.mp4

You can see that it doesn't crash even after changing the theme.

brminnick
brminnick previously approved these changes Feb 17, 2024
@brminnick brminnick enabled auto-merge (squash) February 17, 2024 21:48
@brminnick brminnick enabled auto-merge (squash) February 17, 2024 21:58
@brminnick brminnick changed the title Add Popup disposed check on Android Remove Bindings on Popup Close Feb 17, 2024
@brminnick brminnick merged commit c6654f3 into CommunityToolkit:main Feb 17, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Application crashes on theme change after using Popup with AppThemeBinding under Android
3 participants