ViewModels,消息和生命周期

Chr*_*eeg 2 xamarin.android mvvmcross xamarin

我修改了@ slodge的一个样本,以解决我在ViewModels生命周期中遇到的问题.

我稍微修改了N26:https: //github.com/csteeg/NPlus1DaysOfMvvmCross/tree/viewmodeldisposesample/N-26-Fraggle

这个分支使用mvxmessenger插件来显示出错的地方.代码不漂亮,但显示你的不正确.您可以看到Id = 0的SubViewModel如何继续接收消息,即使它的视图早已消失.并且(在某些时候)HomeViewModel如何停止接收消息.

重现的步骤(包括清理版本的调试输出):

启动应用程序

HomeViewModel:Warning:HomeViewModel 0 received: Created HomeViewModel0

点击按钮'1'

HomeViewModel:Warning:HomeViewModel 0 received: Created SubViewModel0 SubViewModel:Warning:SubViewModel 0 received: Created SubViewModel0 HomeViewModel:Warning:HomeViewModel 0 received: Created FirstViewModel0 SubViewModel:Warning:SubViewModel 0 received: Created FirstViewModel0 FirstViewModel:Warning:FirstViewModel 0 received: Created FirstViewModel0

点击后面

HomeViewModel:Warning:HomeViewModel 0 received: Destroyed FirstView for viewmodel 0 SubViewModel:Warning:SubViewModel 0 received: Destroyed FirstView for viewmodel 0 FirstViewModel:Warning:FirstViewModel 0 received: Destroyed FirstView for viewmodel 0 HomeViewModel:Warning:HomeViewModel 0 received: Destroyed SubFrag for viewmodel 0 SubViewModel:Warning:SubViewModel 0 received: Destroyed SubFrag for viewmodel 0 FirstViewModel:Warning:FirstViewModel 0 received: Destroyed SubFrag for viewmodel 0 HomeViewModel:Warning:HomeViewModel 0 received: Destroyed DubFrag for viewmodel 0 SubViewModel:Warning:SubViewModel 0 received: Destroyed DubFrag for viewmodel 0 FirstViewModel:Warning:FirstViewModel 0 received: Destroyed DubFrag for viewmodel 0 你可以在这里看到被破坏的视图,我希望视图模型能够与它们一起使用

再次单击"1"按钮

HomeViewModel:Warning:HomeViewModel 0 received: Created SubViewModel1 SubViewModel:Warning:SubViewModel 0 received: Created SubViewModel1 FirstViewModel:Warning:FirstViewModel 0 received: Created SubViewModel1 SubViewModel:Warning:SubViewModel 1 received: Created SubViewModel1 HomeViewModel:Warning:HomeViewModel 0 received: Created FirstViewModel1 SubViewModel:Warning:SubViewModel 0 received: Created FirstViewModel1 FirstViewModel:Warning:FirstViewModel 0 received: Created FirstViewModel1 SubViewModel:Warning:SubViewModel 1 received: Created FirstViewModel1 FirstViewModel:Warning:FirstViewModel 1 received: Created FirstViewModel1

在这里,您看到,subviewmodel 0仍在接收消息.我可以告诉它应该停止向没有附加的视图模型发送消息吗?或者视图模型可以知道没有附加

现在,当你继续重复这些步骤很长一段时间,在模拟器中说15次时,一些视图模型将停止接收消息(我猜它们是垃圾收集的).奇怪的是,其中一个观点是HomeViewModel!HomeView永远不会被破坏,但是homeviewmdoel停止接收消息,因此如果你的应用程序需要,那么nog能够相应地更新视图

小智 5

我有类似的情况,MvxMessages仍然被接收并由视图模型执行,视图模型不再附加到视图.

我的解决方案是将以下内容添加到基本视图模型中:

  • 订阅方法
  • 取消订阅操作列表(这是由Subscribe方法添加的)
  • 一个UnsubscribeAll方法

在Android活动OnDestoy中,我调用了viewmodel的UnsubscribeAll.

(作为奖励,因为在取消订阅操作中引用了令牌,我不需要保留其他列表)

BaseViewModel:

    #region Messenger

    /// <summary>
    /// Must set the Messenger object before doing any subscribing
    /// </summary>
    public IMvxMessenger Messenger { get; set; }

    private readonly object _messengerLock = new Object();

    private List<Action> _unsubscribeActions;

    /// <summary>
    /// Subscribe to a message, and store in a list so can be unsubscribed automatically later
    /// </summary>
    /// <typeparam name="TMessage"></typeparam>
    /// <param name="deliveryAction"></param>
    public void Subscribe<TMessage>(Action<TMessage> deliveryAction) where TMessage: MvxMessage
    {
        var messenger = Messenger;
        if (messenger == null) { return; }

        var token = messenger.Subscribe<TMessage>(deliveryAction);

        Action unsubscriber = delegate()
        {
            messenger.Unsubscribe<TMessage>(token);
        };

        lock (_messengerLock)
        {
            if (_unsubscribeActions == null)
            {
                _unsubscribeActions = new List<Action>();
            }
            _unsubscribeActions.Add(unsubscriber);
        }
    }

    /// <summary>
    /// Unsubscribe to all messages which have been previously subscribed to
    /// </summary>
    public void UnsubscribeAll()
    {
        if (_unsubscribeActions == null) { return; }
        lock (_messengerLock)
        {
            foreach (var a in _unsubscribeActions)
            {
                a();
            }
            _unsubscribeActions = null;
        }
    }

    #endregion
Run Code Online (Sandbox Code Playgroud)

BaseActivity:

    protected override void OnDestroy()
    {
        var vm = ViewModel as ViewModel.BaseViewModel;
        if (vm != null) { vm.UnsubscribeAll(); }
        base.OnDestroy();
    }
Run Code Online (Sandbox Code Playgroud)