Vin*_*ams 43 android mvvm android-context dagger-2
我试图在我的Android应用程序中实现MVVM模式.我已经读过ViewModels不应该包含任何特定于Android的代码(以使测试更容易),但是我需要使用上下文来处理各种事情(从xml获取资源,初始化首选项等).做这个的最好方式是什么?我看到它AndroidViewModel有一个对应用程序上下文的引用,但是它包含特定于android的代码,因此我不确定它是否应该在ViewModel中.这些也与Activity生命周期事件有关,但我使用匕首来管理组件的范围,所以我不确定这会如何影响它.我是MVVM模式和Dagger的新手,所以任何帮助都表示赞赏!
小智 32
您可以使用Application它通过提供的上下文AndroidViewModel,你应该继承AndroidViewModel这简直是一个ViewModel包含一个Application参考.
Jac*_*key 23
并不是ViewModels不应该包含Android特定的代码来使测试更容易,因为它是使测试更容易的抽象.
ViewModel之所以不应该包含Context的实例或类似于上下文的其他对象的原因是因为它具有与活动和片段不同的生命周期.
我的意思是,假设您在应用上进行了轮换更改.这会导致您的Activity和Fragment自行销毁,因此它会重新创建.ViewModel意味着在此状态期间保持不变,因此如果它仍然在被破坏的Activity中持有View或Context,则可能会发生崩溃和其他异常.
至于你应该怎么做你想做的事情,MVVM和ViewModel与JetPack的数据绑定组件配合得非常好.对于大多数情况,您通常会存储String,int或etc等,您可以使用Databinding使Views直接显示它,因此不需要将值存储在ViewModel中.
但是如果你不想要Databinding,你仍然可以在构造函数或方法中传递Context来访问Resources.只是不要在ViewModel中包含该Context的实例.
Iva*_*sov 14
正如其他人所提到的AndroidViewModel,您可以从中获取应用程序,Context但从我在评论中收集的内容来看,您正试图@drawable从内部操作s,ViewModel这违背了 MVVM 的目的。
一般来说,需要Context在您的ViewModel几乎普遍存在的情况下建议您应该考虑重新考虑如何划分Views 和ViewModels.
与其ViewModel解析 drawable 并将它们提供给 Activity/Fragment,不如考虑让 Fragment/Activity 根据ViewModel. 比如说,您需要在视图中显示不同的可绘制对象以进行开/关状态——它ViewModel应该保持(可能是布尔值)状态,但相应View地选择可绘制对象是其业务。
数据绑定使它变得非常简单:
<ImageView
...
app:src="@{viewModel.isOn ? @drawable/switch_on : @drawable/switch_off}"
/>
Run Code Online (Sandbox Code Playgroud)
如果您有更多状态和可绘制对象,为了避免布局文件中的笨拙逻辑,您可以编写一个自定义BindingAdapter来将Enum值转换为R.drawable.*引用,例如:
enum class CatType { NYAN, GRUMPY, LOL }
class CatViewModel {
val catType: LiveData<CatType> = ...
Run Code Online (Sandbox Code Playgroud)
// View-tier logic, takes the burden of knowing
// Contexts and R.** refs from the ViewModel
@BindingAdapter("bindCatImage")
fun bindCatImage(view: ImageView, catType: CatType) = view.apply {
val resource = when (value) {
CatType.NYAN -> R.drawable.cat_nyan
CatType.GRUMPY -> R.drawable.cat_grumpy
CatType.LOL -> R.drawable.cat_lol
}
setImageResource(resource)
}
Run Code Online (Sandbox Code Playgroud)
<ImageView
bindCatType="@{vm.catType}"
... />
Run Code Online (Sandbox Code Playgroud)
如果您需要在您的-- 中使用的Context某些组件,请在ViewModel外部创建该组件ViewModel并将其传入。您可以使用 DI 或单例,或Context在初始化ViewModelin Fragment/之前创建依赖组件Activity。
Context是 Android 特定的东西,并且在ViewModels 中依赖它对于单元测试来说是笨拙的(当然,您可以将其AndroidJunitRunner用于特定于 android 的东西,但是拥有更清晰的代码而没有额外的依赖是有意义的)。如果您不依赖Context,则为ViewModel测试模拟所有内容会更容易。因此,经验法则是:除非有充分的理由,否则不要Context在 ViewModel 中使用。
dev*_*jay 13
对于Android体系结构组件视图模型,
将您的活动上下文传递给活动的ViewModel作为内存泄漏不是一个好习惯。
因此,要在您的ViewModel中获取上下文,ViewModel类应扩展Android View Model类。这样,您可以获取上下文,如下面的示例代码所示。
class ActivityViewModel(application: Application) : AndroidViewModel(application) {
private val context = getApplication<Application>().applicationContext
//... ViewModel methods
}
Run Code Online (Sandbox Code Playgroud)
小智 12
在希尔特:
@Inject constructor(@ApplicationContext context : Context)
Run Code Online (Sandbox Code Playgroud)
Vin*_*ams 11
我最终做的不是直接在ViewModel中使用Context,而是创建了像ResourceProvider这样的提供程序类,它可以为我提供所需的资源,并且我将这些提供程序类注入到我的ViewModel中
TL;DR:通过 Dagger 在您的 ViewModel 中注入应用程序的上下文并使用它来加载资源。如果您需要加载图像,请通过数据绑定方法的参数传递 View 实例并使用该 View 上下文。
MVVM 是一个很好的架构,它绝对是 Android 开发的未来,但有一些东西仍然是绿色的。以 MVVM 架构中的层通信为例,我见过不同的开发人员(非常知名的开发人员)使用 LiveData 以不同的方式来通信不同的层。其中一些使用 LiveData 将 ViewModel 与 UI 进行通信,但随后它们使用回调接口与存储库进行通信,或者它们具有交互器/用例并使用 LiveData 与它们进行通信。点这里,是不是一切都100%的定义还没有。
话虽如此,我解决您的具体问题的方法是通过 DI 提供应用程序的上下文,以便在我的 ViewModel 中使用,以从我的 strings.xml 中获取诸如 String 之类的东西
如果我正在处理图像加载,我会尝试从数据绑定适配器方法传递 View 对象并使用 View 的上下文来加载图像。为什么?因为如果您使用应用程序的上下文加载图像,某些技术(例如 Glide)可能会遇到问题。
希望能帮助到你!
您可以getApplication().getApplicationContext()从ViewModel中访问应用程序上下文。这是访问资源,首选项等所需的。
简短答案-不要这样做
为什么呢
它破坏了视图模型的全部目的
通过使用LiveData实例和各种其他推荐的方法,您几乎可以在视图模型中做的所有事情都可以在活动/片段中完成。
小智 6
这是一种将 Context 引入 ViewModel 的方法
private val context = getApplication<Application>().applicationContext
Run Code Online (Sandbox Code Playgroud)
具有对应用程序上下文的引用,但是它包含特定于 android 的代码
好消息,你可以使用 Mockito.mock(Context.class)在测试中并使上下文返回您想要的任何内容!
因此,只需ViewModel像往常一样使用 a ,并像往常一样通过 ViewModelProviders.Factory 为其提供 ApplicationContext 。
| 归档时间: |
|
| 查看次数: |
28771 次 |
| 最近记录: |