当应用程序重新启动时,来自Xamarin消息传递中心的多条消息

本文关键字:消息 消息传递 Xamarin 重新启动 应用程序 来自 | 更新日期: 2023-09-27 18:08:21

我有一个Xamarin Forms应用程序,其中我使用MessagingCenter从特定平台向Xamarin.Forms应用程序发送一些数据。

在我的Page中,我在base.OnAppearing()中订阅消息,并在base.OnDisappearing()方法中取消订阅。

我遇到的问题是,当应用程序被AndroidOS停止时(例如,当我改变设备的语言时),我开始获得消息的副本。我很困惑为什么会发生这种情况,但我注意到当应用程序重新启动时不调用base.OnDisappearing()方法。

有没有人知道什么可能导致我的问题和如何解决它?另外,在Xamarin中有任何方法可以看到你所有的发布者和订阅者吗?

当应用程序重新启动时,来自Xamarin消息传递中心的多条消息

就像Greensy说的,除了在OnAppearing()中订阅和在OnDisappearing()中取消订阅外,我还在订阅之前取消订阅消息,因为,为什么不呢:

protected override async void OnAppearing() {
    base.OnAppearing();
    MessagingCenter.Unsubscribe<string>(this, "KeyHere");
    MessagingCenter.Subscribe<string>(this, "KeyHere", string => { }));
}

不使用OnAppearingOnDisappearing,您可以在页面构造函数中在InitializeComponent()之后订阅它,并像这样取消订阅:

protected override void OnParentSet()
{
    base.OnParentSet();
    if (Parent == null)
    {
        // unsubscribe 
    }
}

OnParentSetOnAppearing之前,OnDisappearing之后被调用。但是,只有在从导航堆栈中删除父元素或弹出页面时,父元素才会在页面上变为空。这确保了它们都只被调用一次,而我注意到OnAppearingOnDisappearing并不总是一致地调用,这取决于弹出窗口和/或其他东西可能显示的方式。

In Xamarin。表单v2.3.4.247,在Android上,在测试中,我们发现,当一个模态页面是在导航页的顶部,你离开应用程序,导航页有它的ondisappear()方法被调用,而不是模态页面,实际上是在顶部。为了解决这个问题,我们做了以下工作:-在onappear方法中,检查你是否真的在上面-如果你在上面,一切都很好-如果你不在顶部,调用sendvanishing()在你自己,sendappear()在实际页面顶部。我们还发现需要在最上面的页面上调用sendvanishing(),因为Xamarin表单保护这些方法不被多次调用。换句话说,如果你调用sendvanishing()两次,它只会做一次。

下面是一个为我们工作的例子,因为我们有一个BaseContentPage,所有的页面都是从它派生的:

protected override void OnAppearing()
{
    base.OnAppearing();
    var pageOnTop = ModalContentPageOnTop();
    if (pageOnTop == null || pageOnTop == this)
    {
        // do some stuff, like setting up subscriptions
        SetupSubscriptions();
    }
    else
    {
        // Xamarin Forms Appearing/Disappearing Bug
        // Found that when you leave the Android app with a modal page on top of a non-modal page (either minimise the app or lock the device), then Xamarin.Forms does not properly call OnAppearing. 
        // Xamarin.Forms will call OnAppearing on the non-modal page and not on the modal page. This would not only cause message subscriptions to not be set up on the modal page, 
        // but would also set up message subscriptions on the non-modal page. Not good.  Hopefully, this work-around should stop being executed when Xamarin fixes the problem, as we won't 
        // fall into this "else" condition above, because OnAppearing will be called on the right page.
        // NOTE: SendDisappearing and SendAppearing have boolean guards on them. If SendAppearing was called last, calling it again will do nothing.
        // SendDisappearing has the same behaviour. Thus we need to call SendDisappearing first, to be guaranteed that SendAppearing will cause the OnAppearing() method to execute.
        ((IPageController)pageOnTop).SendDisappearing();  // try and correct Xamarin.Forms - the page actually on top was not told it was disappearing - tell it now
        ((IPageController)this).SendDisappearing();  // try and correct Xamarin.Forms - if it thinks the view has appeared when it hasn't, it won't call OnAppearing when it is truly appearing.
        ((IPageController)pageOnTop).SendAppearing();  // try and correct Xamarin.Forms by notifying the correct page that it is appearing
    }
}

其中ModalContentPageOnTop看起来像:

private ContentPage ModalContentPageOnTop()
{
    var page = Navigation.ModalStack.LastOrDefault();
    var navigationPage = page as NavigationPage;
    if (navigationPage != null)
        return navigationPage.CurrentPage as ContentPage;
    return page as ContentPage;
}

我们的应用中有一个非常浅的导航层次结构,所以这种方法可能不适用于更复杂的导航堆栈(如模态页面推送其他页面或其他模态页面)

问题被证明与Xamarin没有直接关系。表单,但由于MainActivity类中的OnStop方法中没有正确取消注册BroadcastReceiever的问题。因此,每当应用程序经过OnStop/OnStart周期时,将发送2条消息,即使我只有一个活动订阅。

我还在Xamarin的OnDisappearing方法中调用Unsubsribe。form ContentPages,并且在OnAppearing方法中调用Subscribe之前也调用Unsubscribe

到目前为止,我还没有在任何设备或不同的Android版本上再次出现这个问题。

还有一些额外的建议,永远不要忘记取消订阅任何剩余的MessagingCenter订阅,否则你会遇到一些奇怪的bug,这会让你的头发变白。有一篇关于这个话题的好文章,但是我找不到了。