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

时间:2014-06-10 15:49:00

标签: android-fragments xamarin.android mvvmcross

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

问题 - 在混合片段和基本视图并使用设备上的设置时 - “开发者选项/不保留活动”如果调用OnDestory(),则ViewModel为null,然后活动为重新回到视野中。这会导致空引用异常和应用程序崩溃。

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

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

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

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

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

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

登录后显示登录屏幕

  • OnCreate中
  • 的OnStart
  • 崩溃,空引用异常

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

作为参考点,我基于滑动菜单的项目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,最坏的情况是重新创建它们,如果片段是从内存中卸载的。

1 个答案:

答案 0 :(得分:6)

从您的代码中,您首次创建时看起来像手动设置了片段的ViewModel:

            frag.ViewModel = viewModelLocal;

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

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

要解决此问题,您需要:

  • 找到某种方法在ViewModel出现OnCreateView期间重新创建bundle。您可以使用序列化/反序列化技术或在OnCreateView方法中移动ViewModel=viewModelLocal代码而不是在拥有Activity
  • 内部来执行此操作
  • 阻止默认的Android片段重新创建(例如,阻止父bundle使用其OnCreate bundle并使用您自己的重新充气逻辑)

注意:Activity不会发生此行为,因为MvvmCross可以在那里重用Intent,以便为Activity重新创建ViewModel。但是对于Fragment s,应用程序负责创建这些(在其自定义演示者中),因此目前应用程序也必须负责重新创建ViewModel