Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MvvmCross: Best way to raise event in ViewModel?

I currently have a View (Android Fragment) and a coresponding ViewModel. I now want to raise an event in the ViewModel which the View can subscribe to.

What's the best way to archive this? I heard a regular C# event (delegate) can lead to memory leaks? Is this the reason for the WeakSubscribe function? How to bind it to an event?

like image 603
Ranga B. Avatar asked Sep 04 '16 09:09

Ranga B.


2 Answers

To prevent memory leaks in your views, every event you subscribed to needs to be unsubscribed from, either way using WeakSubscribe or subscribing to events as usual.

A common scenario would be subscribing on:

  • Android OnResume()
  • iOS ViewWillAppear()

then dispose the subscription on:

  • Android OnPause()
  • iOS ViewWillDisappear()

WeakSubscribe

If you want to "listen" for ViewModel property changes, WeakSubscribe comes in handy:

private IDisposable _selectedItemToken;

_selectedItemToken = ViewModel.WeakSubscribe(() => 
    ViewModel.SelectedItem, (sender, eventArgs) => {
        // do something
});

Just notice that WeakSubscribe() returns an MvxWeakEventSubscription that is also IDisposable. You need to save a reference to that subscription in your view and dispose it when thew view is no longer needed. There are two reasons to keep that reference:

  1. You can dispose it later
  2. If you don´t keep it, your lambda event handler may not always work

Later on...

_selectedItemToken?.Dispose();

Normal event subscription

If you just need to subscribe to another kind of event (not property changes) in your ViewModel, you don´t actually need WeakSubscribe. You can just add an event listener to the ViewModel, as you would do with any object.

ViewModel.AnEvent += YourDelegate;

Later on...

ViewModel.AnEvent -= YourDelegate;

Don´t forget the last step. That will prevent memory leaks. As I said, Android OnPause() and iOS ViewWillDisappear() are good places to do it.

That way your ViewModel won´t be stuck in memory when the view is disposed thus your view can be garbage collected correctly.

like image 126
xleon Avatar answered Sep 21 '22 22:09

xleon


You can create a leak if you subscribe to an event in a temporary object and don't unsubscribe before releasing the temporary object. Little chance for that in your case as the view model most likely will be created only once.

Since you are using mvvm, an alternative to events are Messengers which you can find implemented in popular mvvm-frameworks like MvvmLight or MvvmCross. This gives you truly decoupled events as you only need to know the format of the message and don't need to know anything about the sender (which in your case is the ViewModel). With messenger you only subscribe to a message-type and the sender can be anywhere in the app.

like image 36
Njål Eide Avatar answered Sep 19 '22 22:09

Njål Eide