【问题标题】:MvvmCross Android - Null Reference for ViewModel when Reloading FragmentsMvvmCross Android - 重新加载片段时 ViewModel 的空引用
【发布时间】:2014-07-31 11:26:39
【问题描述】:

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

问题 - 在混合片段和基本视图并使用设备上的设置时 - 如果 OnDestory() 被调用并且活动被调用,则“开发人员选项/不保留活动”视图模型为空带回了视野。这会导致空引用异常和应用程序崩溃。

说明 我在 Android 中有一个使用 MvvmCross 的滑出/汉堡菜单。在应用程序启动时,会发生以下步骤:

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

  • LoginViewModel 不是一个片段,只是一个普通的基础视图。显示给用户

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

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

  • 创建时
  • StartActivityForResult
  • 开机
  • OnResume
  • 暂停
  • OnSaveInstanceState
  • OnStop
  • OnDestroy

登录后显示登录屏幕

  • 创建时
  • 开机
  • 崩溃、空引用异常

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

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

【问题讨论】:

    标签: android-fragments xamarin.android mvvmcross


    【解决方案1】:

    从您的代码来看,您似乎是在首次创建片段时手动设置片段的 ViewModel:

                frag.ViewModel = viewModelLocal;
    

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

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

    要解决此问题,您需要:

    • bundle 存在时,找到某种方法在OnCreateView 期间重新创建您的ViewModel。您可以使用序列化/反序列化技术或通过将 ViewModel=viewModelLocal 代码移动到 OnCreateView 方法而不是拥有 Activity
    • 阻止默认的 Android 片段重新创建(例如,通过阻止父级 bundle 使用其 OnCreate bundle 并使用您自己的再膨胀逻辑)

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

    【讨论】:

      猜你喜欢
      • 2015-01-14
      • 1970-01-01
      • 2014-01-09
      • 1970-01-01
      • 1970-01-01
      • 2012-12-15
      • 2016-11-24
      • 2015-11-16
      相关资源
      最近更新 更多