我修改了@ 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
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
你可以在这里看到被破坏的视图,我希望视图模型可以随身携带
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停止接收消息, 因此,如果您的应用需要
,则能够相应地更新视图答案 0 :(得分:5)
我遇到了类似的情况,MvxMessages仍然被接收并且由不再附加到视图的视图模型执行。
我的解决方案是将以下内容添加到基本视图模型中:
在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
BaseActivity:
protected override void OnDestroy()
{
var vm = ViewModel as ViewModel.BaseViewModel;
if (vm != null) { vm.UnsubscribeAll(); }
base.OnDestroy();
}
答案 1 :(得分:4)
MvvmCross v3不会将ViewModel暴露给任何View生命周期事件,如ViewDidAppear / Disappear,OnNavigatedTo / From,OnPause / OnResume / OnDestroy。
原因是:
ViewDidUnload
中发现了iOS更改并且一般都支持iOS(当视图已经过时很难解决)相反,MvvmCross v3使用垃圾收集来整理ViewModel。为了帮助这个Mvx,总是使用ViewModel-to-View和MessageHub-to-ViewModels中的WeakReference
。接下来的一般理念是:
话虽如此,如果GarbageCollection对您的应用程序来说不够及时,那么MvvmCross确实允许您使用新功能扩展ViewModel
。例如,如果您愿意,可以轻松添加新的IViewLifecycleAware
界面。这很容易做到,但是一旦完成,那么您的应用程序有责任确保从您支持的每个平台上的相应View事件/覆盖中调用接口。
关于这个话题还有一点:
对于HomeViewModel
停止接收邮件的具体问题,我认为这是因为您没有存储订阅令牌。
因为默认情况下MvvmCross信使使用弱引用,所以必须存储订阅令牌 - 当处理该令牌或垃圾收集时,订阅将被取消订阅。
所以你的代码:
public class HomeViewModel
: MvxViewModel
{
public static int IdCounter = 0;
public int Id = IdCounter++;
public HomeViewModel()
{
var messenger = Mvx.Resolve<IMvxMessenger>();
messenger.Subscribe<JustAMessage>(OnMessage);
messenger.Publish(new JustAMessage(this) { Message = "Created HomeViewModel" + Id });
}
// ...
需要:
public class HomeViewModel
: MvxViewModel
{
public static int IdCounter = 0;
public int Id = IdCounter++;
private IDisposable _token;
public HomeViewModel()
{
var messenger = Mvx.Resolve<IMvxMessenger>();
_token = messenger.Subscribe<JustAMessage>(OnMessage);
messenger.Publish(new JustAMessage(this) { Message = "Created HomeViewModel" + Id });
}
// ...
有更多相关内容: