You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切出MVVMCross应用时IMvxNavigationService导航任务取消问题咨询

问题定位

这是MvvmCross 8.x版本在Android平台的已知预期行为,不是代码bug:
Android系统会在应用切后台、内存不足或者开启「不保留活动」开发者选项时,销毁不可见的Activity页面,对应ViewModel2的View触发ViewDestroy生命周期时,MvvmCross默认的导航服务会自动取消等待返回结果的异步任务,因此ViewModel1侧会抛出TaskCanceledException。

解决方案

下面是三种可落地的解决方式,可根据业务场景选择:

方式1:修改导航服务默认配置(最简单)

MvvmCross 8.0.1支持配置导航任务的取消逻辑,不需要修改业务代码,在Android平台的Setup类中添加如下配置,即可全局关闭View销毁时自动取消导航任务的逻辑:

protected override void FillNavigationParams(IMvxNavigationService navigationService)
{
    navigationService.CancelTasksOnViewDestroy = false;
}

如果只需要对ViewModel2生效,不需要全局修改,可以在ViewModel2对应的Android页面(继承自MvxActivity或MvxFragment)中重写销毁逻辑,阻止ViewModel被回收:

protected override void OnDestroy()
{
    // 不将ViewModel置空,保留实例
    base.ViewModel = null;
    base.OnDestroy();
}

方式2:改用事件/状态持久化传递结果(最稳定)

避免依赖导航返回的异步Task传递结果,改用MvvmCross自带的MvxMessenger事件总线或者全局状态容器传递结果,不受页面/ViewModel生命周期影响:

  1. 定义返回结果消息类:
public class ViewModel2ResultMessage : MvxMessage
{
    public string Result { get; }
    public ViewModel2ResultMessage(object sender, string result) : base(sender)
    {
        Result = result;
    }
}
  1. ViewModel2关闭时发布消息:
private async Task CloseView()
{
    var result = "要返回的结果";
    Mvx.IoCProvider.Resolve<IMvxMessenger>().Publish(new ViewModel2ResultMessage(this, result));
    await this.navSvc.Close(this, result);
}
  1. ViewModel1初始化时订阅消息,提前接收结果:
private readonly IMvxMessenger _messenger;
private string _viewModel2Result;
public ViewModel1(IMvxMessenger messenger)
{
    _messenger = messenger;
    _messenger.Subscribe<ViewModel2ResultMessage>(msg => 
    {
        _viewModel2Result = msg.Result;
    });
}
  1. ViewModel1导航逻辑中捕获取消异常,直接使用提前收到的结果:
private async Task ShowView()
{
    try
    {
        var output = await navSvc.Navigate<ViewModel2, string, string>(string.Empty);
        // 正常流程拿到结果
        ProcessResult(output);
    }
    catch (TaskCanceledException)
    {
        // 任务被取消时使用订阅到的结果
        ProcessResult(_viewModel2Result);
    }
    catch (Exception ex)
    {
        // 其他异常处理
    }
}

方式3:手动临时缓存结果(最轻量化)

如果不想引入事件总线,可以在ViewModel2的任意生命周期节点(比如输入结果变更时)就把要返回的结果存入内存缓存/SharedPreferences,ViewModel1捕获到取消异常时直接读取缓存即可,适合逻辑简单的场景。

注意事项

如果选择保留ViewModel实例的方式,需要手动管理ViewModel的生命周期,在确认不需要使用后手动释放资源,避免出现内存泄漏。

内容的提问来源于stack exchange,提问作者Christopher Pope

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 12:27:02