Reputation: 648
I have a Xamarin Forms
application in which I use MessagingCenter
to send some data from specific platform to Xamarin.Forms
application.
In my Page
I subscribe to messages in base.OnAppearing()
and unsubscribe in base.OnDisappearing()
method. This works as expected.
The problem I'm having is that when application get's stopped by the AndroidOS
(example of this is when I change the language of device) I start getting copies of messages. I'm confused why this is happening but I noticed that base.OnDisappearing()
method is not called when application is restarted.
Does anyone have any idea what could cause my problem and how to fix it?
Also, is there any way in Xamarin
to see all your publishers and subscribers?
Upvotes: 4
Views: 5984
Reputation: 648
The problem turned out to not be directly related with Xamarin.Forms, but was due to a problem of not properly unregistering the BroadcastReceiever
in the OnStop
method inside my MainActivity
class. So whenever the application went through OnStop/OnStart
cycle, 2 messages would be sent, even though I had only one active subscription.
I also call Unsubsribe
in my OnDisappearing
method on Xamarin.Forms ContentPages, and also call Unsubscribe
before calling Subscribe
in OnAppearing
method.
So far I haven't had this issue again on any of devices or different Android versions.
And some additional advice, don't ever forget to Unsubscribe any remaining MessagingCenter subscriptions you have in the OnDisappearing method otherwise you are in for some weird bugs, that will make your hair turn gray. There was a nice article on that topic, but I can't find it again.
Upvotes: 0
Reputation: 31
In Xamarin.Forms v2.3.4.247, on Android, in testing, we found that when a modal page was on top of a navigation page, and you leave the app, the navigation page had its OnDisappearing() method called instead of the modal page that is actually on top. To work around, we did the following: - In the OnAppearing method, check if you're actually on top - if you are on top, all good - if you're not on top, call SendDisappearing() on yourself, and SendAppearing() on the actual page on top. We also found that you needed to call SendDisappearing() on the page on top, since Xamarin forms protects these methods from multiple calls. In other words, if you call SendDisappearing() twice, it will only do something once.
Here's an example which worked for us, as we have a BaseContentPage from which all pages are derived:
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
}
}
where ModalContentPageOnTop looks like:
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;
}
We had a very shallow navigation hierarchy in our app, so this approach may not work with more complicated navigation stacks (ie modal pages that push other pages or other modal pages)
Upvotes: 1
Reputation: 3251
Instead of using OnAppearing
and OnDisappearing
you could subscribe to it after InitializeComponent()
in the page constructor and unsubscribe like so:
protected override void OnParentSet()
{
base.OnParentSet();
if (Parent == null)
{
// unsubscribe
}
}
OnParentSet
gets called before OnAppearing
and after OnDisappearing
. However, the Parent only becomes null on a Page after it is removed from the navigation stack or when popping the page. This ensures they both only get called once while I've noticed OnAppearing
and OnDisappearing
aren't always called consistently depending on how pop-ups and/or other things might be shown.
Upvotes: 1
Reputation: 11105
Like Greensy said, in addition to subscribing in OnAppearing()
and unsubscribing in OnDisappearing()
, I also unsubscribe from the message before subscribing because, why not:
protected override async void OnAppearing() {
base.OnAppearing();
MessagingCenter.Unsubscribe<string>(this, "KeyHere");
MessagingCenter.Subscribe<string>(this, "KeyHere", string => { }));
}
Upvotes: 3