How to get Context in Android MVVM ViewModel
Solution 1:
You can use an Application
context which is provided by the AndroidViewModel
, you should extend AndroidViewModel
which is simply a ViewModel
that includes an Application
reference.
Solution 2:
For Android Architecture Components View Model,
It's not a good practice to pass your Activity Context to the Activity's ViewModel as its a memory leak.
Hence to get the context in your ViewModel, the ViewModel class should extend the Android View Model Class. That way you can get the context as shown in the example code below.
class ActivityViewModel(application: Application) : AndroidViewModel(application) {
private val context = getApplication<Application>().applicationContext
//... ViewModel methods
}
Solution 3:
It's not that ViewModels shouldn't contain Android specific code to make testing easier, since it's the abstraction that makes testing easier.
The reason why ViewModels shouldn't contain an instance of Context or anything like Views or other objects that hold onto a Context is because it has a separate lifecycle than Activities and Fragments.
What I mean by this is, let's say you do a rotation change on your app. This causes your Activity and Fragment to destroy itself so it recreates itself. ViewModel is meant to persist during this state, so there's chances of crashes and other exceptions happening if it's still holding a View or Context to the destroyed Activity.
As for how you should do what you want to do, MVVM and ViewModel works really well with the Databinding component of JetPack. For most things you would typically store a String, int, or etc for, you can use Databinding to make the Views display it directly, thus not needing to store the value inside ViewModel.
But if you don't want Databinding, you can still pass the Context inside the constructor or methods to access the Resources. Just don't hold an instance of that Context inside your ViewModel.
Solution 4:
Short answer - Don't do this
Why ?
It defeats the entire purpose of view models
Almost everything you can do in view model can be done in activity/fragment by using LiveData instances and various other recommended approaches.
Solution 5:
What I ended up doing instead of having a Context directly in the ViewModel, I made provider classes such as ResourceProvider that would give me the resources I need, and I had those provider classes injected into my ViewModel