【问题标题】:Can I get the context inside ViewModel's init block?我可以在 ViewModel 的 init 块中获取上下文吗?
【发布时间】:2021-03-16 15:39:12
【问题描述】:

我正在为我的应用程序实现离线模式,我的计划是将本地数据库放在 UI 和 API 请求之间。

我有这个片段和他的带有这个初始化块的视图模型:

init {
   viewModelScope.launch(Dispatchers.IO) {
      // context required here
      loadVehicles()
   }
}

现在,在 loadVehicles 中,我想检查我是否在线,如果在线,我将简单地调用 API 以更新我的本地数据库,以防有任何新内容。

fun isOnline(context: Context): Boolean {
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    if (connectivityManager != null) {
        val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
        if (capabilities != null) {
            return true
        }
    }
    return false
}

这是我能找到的用于测试我是否在线的最简单的代码,并且此函数需要上下文,而该上下文无法从视图模型的 init 块中访问。

如果有什么我可以改进的,期待听到其他关于做事的建议。

【问题讨论】:

  • 我可以在 ViewModel 的 init 块中获取上下文吗?AndroidViewModel 派生你的 ViewModel 吗?
  • 这是标题建议还是什么?我很困惑。所以你要添加“从 AndroidViewModel 派生”,嗯,是的,肯定是......如果那对你来说是模棱两可的
  • 然后将初始化代码移动到构造函数
  • 还有为什么上下文是不可访问的? It should be
  • 我不能,它必须是协程,我正在向本地数据库提出改造和空间的请求,以及从 API 获取新数据,所有这些都是暂停的函数。

标签: android kotlin mvvm dagger-2


【解决方案1】:

您的代码“必须”如下所示:

class SomeHelperClass @Inject constructor(private val  context: Context) {

    fun isOnline(): Boolean {
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (connectivityManager != null) {
            val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
            if (capabilities != null) {
                return true
            }
        }
        return false
    }
}


class MyViewModel @Inject constructor(helper: SomeHelperClass):ViewModel()  {
    init {
        viewModelScope.launch(Dispatchers.IO) {

            // call to helper.isOnline() !!!!!!

            loadVehicles()
        }
    }
}
  • 这就是MyViewModel中的代码不会依赖于上下文, 这意味着不需要仪器测试。你可以用 普通的 Kotlin/Java 测试。

  • 我知道您可能不想测试它,但其中一种是好的 测试的结果是它使代码更好。 如果你让 可测试的代码,即使你不测试它也会更好。 在这种情况下,您不会制作繁重的 ViewModel,这是一个坏主意。

  • 另外,如果您不使用它,我建议您使用 Dagger-Hilt 已经 - @Inject

【讨论】:

  • 如果@Inject Dagger-Hilt,比是的,我正在使用它,但我不明白为什么我不能直接注入上下文,不是一回事吗?如果我在 Helper 类中注入上下文并在 ViewModel 中注入 helper 类。我开始放慢转换代码的速度,因此我没有将上下文作为参数发送给函数,而是使用了我几乎在任何地方都使用过的实用程序.context,因此,无论如何,我在每个视图模型中都有上下文。
  • 您没有每个 ViewModel 中的上下文。助手类具有上下文。因此,您可以在没有 Android 环境的情况下模拟帮助程序类并执行 ViewModel。如果您想将助手类和 ViewModel 拆分到不同的模块中,您所说的可能是有道理的。比在 VM 模块中拥有一个接口并在另一个模块中拥有帮助器类来实现它更有意义。这将使 VM 的整个模块“不依赖于上下文”。如果你想做就去做吧。但无论哪种情况,你都有一些胜利。
  • 另外,它是关于原则的。这不仅仅是关于你现在通过具体决定赢得什么。这也关乎这个决定将来会给你带来什么。您拆分的东西越多,您就越能防止自己和您的同事将来通过将所有东西都放在一个地方而弄得一团糟。否则 3 个月后有人会说:“哦,太好了!我在这里有一个上下文!让我在这里调用我的代码!”
  • 有见地,我仍然找到更好的做事方式,我现在只有几个月的 Android “认真”编码。谢谢!
  • 基本上,我的想法是基于 Robert Martin 和 SOLID 的 Clean Code 原则。但在 Android 现实中,如果你做错了最终结果是 ViewModel 太大,它处理了很多逻辑。大多数人完全打破了 SRP 的想法。
猜你喜欢
  • 1970-01-01
  • 2011-05-18
  • 1970-01-01
  • 2012-04-29
  • 2015-07-09
  • 2019-02-17
  • 2018-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多