MvvmCross Android - 重新加载片段时ViewModel的空引用

ben*_*ben 3 xamarin.android android-fragments mvvmcross

源代码 - https://github.com/benhysell/V.FlyoutTest/

问题 - 在混合片段和基本视图并使用设备上的设置时 - "开发人员选项/不保持活动"如果调用OnDestory(),则ViewModel为null,然后将活动带回视图.这会导致空引用异常和应用程序崩溃.

说明 我使用MvvmCross在Android中有一个滑出/汉堡菜单.在应用程序启动时,将执行以下步骤:

  • HomeViewModel设置为加载
  • HomeViewModel加载HomeView设置滑出/汉堡菜单
  • 由于HomeView从未真正显示过,只需管理它调用的片段并显示EnterTimeViewModel,默认视图以及我们真正关心的视图.
  • 在加载HomeView结束时,使用messenger插件生成一条消息,以"登录"到系统
  • 在EnterTimeViewModel中收到消息,通常在这里我们会进行某种检查以查看我们是否已登录,但在这种情况下,我们只需使用LoginViewModel调用ShowViewModel来模拟登录请求并提示用户.

  • LoginViewModel不是一个fragement,只是一个普通的基本视图.它向用户显示

  • 在发生这种情况时,HomeView正在从系统中删除,因为我们设置了"开发人员选项/不保留活动"
  • 用户通过登录登录进入系统,在演示中这是一个无操作,它只是关闭LoginView
  • 然后恢复HomeView,除了在恢复期间,EnterTimeViewModel为null ...当EnterTime视图尝试访问EnterTimeViewModel时,将触发null引用.

在加载和卸载HomeView时,关于MvvmCross转换的事件序列如下:

  • 在OnCreate
  • StartActivityForResult
  • 的OnStart
  • 的onResume
  • 在onPause
  • 的onSaveInstanceState
  • 调用OnStop
  • 的OnDestroy

登录后显示登录屏幕

  • 在OnCreate
  • 的OnStart
  • 崩溃,null引用异常

感觉好像跳过了几个步骤,导致崩溃.想法?去看的地方?

作为参考,我基于滑动菜单的项目,https://github.com/jamesmontemagno/Xam.NavDrawer表现出同样的问题.

更新 实施了修复http://benjaminhysell.com/archive/2014/06/mvvmcross-flyoutnavigation-hamburger-menu-sliding-menu-for-android-null-reference-exception-on-fragment-shown-fix/,tldr - 负责尝试保存ViewModel,最坏的情况是重新创建它们,如果片段是从内存中卸载的.

Stu*_*art 6

在您的代码中,看起来您在第一次创建片段时手动设置片段的V​​iewModel:

            frag.ViewModel = viewModelLocal;
Run Code Online (Sandbox Code Playgroud)

来自https://github.com/benhysell/V.FlyoutTest/blob/master/V.FlyoutTest.Droid/Views/HomeView.cs#L153

当您的托管Activity由于"不要保留活动"而被拆除然后再次显示时,Android会将片段状态保存在instanceState包中,并且它将尝试重新创建这些片段 - 这些(我猜)就是当你看到你的NullReferenceException.

要解决这个问题,您需要:

  • 找到一些方法来重现你的存在ViewModel期间.您可以使用序列化/反序列化技术或通过移动OnCreateView方法中的代码而不是拥有内部代码来执行此操作OnCreateViewbundleViewModel=viewModelLocalActivity
  • 阻止默认的Android片段重新创建(例如,通过阻止父级bundle使用它OnCreate bundle并使用您自己的重新通胀逻辑)

注意:这种情况不会发生,Activity因为MvvmCross可以重用Intent那里以便为Activity重新创建ViewModel.但对于Fragments来说,应用程序已经负责创建这些(在其自定义演示者中),因此目前应用程序也必须承担重新创建它的责任ViewModel.