MvvmCross Android - ViewModel never garbage collected

983 views Asked by At

I noticed that MvxMessenger subscriptions were being invoked multiple times due to multiple instances of the same ViewModel. I read a bit about unsubscribing and disposing the tokens (which works and prevents multiple invocations) but I wanted to see the ViewModel being garbage collected naturally and the Messenger subscription along with it.

I wanted to set up a test project for Android similar to this one https://github.com/slodge/MessengerHacking. So here are the two ViewModels

public class FirstViewModel : MvxViewModel
{
    private string _hello = "Hello MvvmCross";
    public string Hello
    { 
        get { return _hello; }
        set { _hello = value; RaisePropertyChanged(() => Hello); }
    }

    private MvxCommand _showSecond;
    public ICommand ShowSecond {
        get {
            _showSecond = _showSecond ?? new MvxCommand(() => ShowViewModel<SecondViewModel> ());
            return _showSecond;
        }
    }
}

And

public class SecondViewModel : MvxViewModel
{
    private readonly IMvxMessenger _messenger;
    private readonly MvxSubscriptionToken _token;

    public SecondViewModel(IMvxMessenger messenger) {
        _messenger = messenger;
        _token = _messenger.Subscribe<MyMessage> ((message) => {
            Debug.WriteLine("incoming message");
        });
    }

    private MvxCommand _send;
    public ICommand Send {
        get {
            _send = _send ?? new MvxCommand(() => _messenger.Publish (new MyMessage (this)));
            return _send;
        }
    }

    private MvxCommand _garbageCollect;
    public ICommand GarbageCollect {
        get {
            _garbageCollect = _garbageCollect ?? new MvxCommand(() => GC.Collect ());
            return _garbageCollect;
        }
    }
}

Then I just have two MvxActivities bound to these ViewModels. If I go to SecondViewModel and click send I see the subscribed event fire off once. If I go back and forth between the First and SecondViewModel these event subscriptions build up and clicking Send fires each of them. Clicking GarbageCollect doesn't seem to make any difference (I'm hoping to see it invoked only once after clicking this).

It feels as though when I click the back button from SecondViewModel, once the MvxActivity is destroyed then SecondViewModel should be eligible for garbage collection.

Another thing I noticed is that even if I Subscribe without saving it into a token, the behaviour is the same. The only way I have successfully got the events to stop firing is by saving the token and calling Unsubscribe or Dispose on the token, however it feels like SecondViewModel is still not getting garbage collected in this case.

Could this be something to do with the recent changes to Xamarin.Android? Or is there something I just don't get!

Many thanks

1

There are 1 answers

1
Mehdi On

I know it is too late for answer, but for the sake of reference:

Short Answer:

In view(MvxActivity), handle DestroyCalled event like this:

DestroyCalled += (s, e) =>
{
    if (ViewModel is IDisposable)
        (ViewModel as IDisposable).Dispose();
};

In viewmodel, implement IDisposable interface:

public new void Dispose()
{
    base.Dispose();
    //Unsubscribe messages here
}

Long Answer:

http://slodge.blogspot.co.uk/2013/11/n42-is-my-viewmodel-visible-can-i-kill.html