Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Context in Android MVVM ViewModel

People also ask

Can we get context in ViewModel?

If the ViewModel needs the Application context, for example to find a system service, it can extend the AndroidViewModel class and have a constructor that receives the Application in the constructor, since Application class extends Context .

Should we use context in ViewModel?

Don't Pass Context I've seen many developers pass context to ViewModel functions, even though the main purpose of using ViewModels is to separate heavy-lifting tasks from UI-related code.


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.


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 

}

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.


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.


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