How to Get Context in Android Mvvm Viewmodel

How to get Context in Android MVVM ViewModel

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

MVVM - get context in a Model class

Your solution works but you break the Dependency Inversion rule in MVVM pattern. So you should implement Dependency Injection pattern using constructor injection or frameworks like Dagger to pass the context to your model layer. Your memory leak is because of breaking this rule too and by implementing Dependency Injection there is no need for global variables with multiple access in different layers which can cause memory leaks.

Android MVVM. Passing objects that has Context as dependency

you can extend your MainViewModel from AndroidViewModel(application: Application) instead of ViewModel.
now you can use your MainViewModel just like befor and application instance can be used to register your broadcastReceiver

class MainViewModel(application: Application) : AndroidViewModel(application) {

}

in activity/fragment

val viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

It's the right and easy one.

should all the things that require context like location receiver, broadcast receiver, ... should be handled in view aka activity level?

Not all of them. I used to work on an application that tracks user location. Since the app needs to track user location for a long period of time with other operations working at the same time. I decided to do it in another thread and let the ViewModel broadcasts the result respectively. Repository also needs context to build Room database. ViewModel will need context to instantiate the repository. That's why we have AndroidViewModel over ViewModel. If you wish you can implement Dependency Injection to avoid this dependency stuff

Can I get the context inside ViewModel's init block?

Your code "must" look like this:

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()
}
}
}
  • That is how the code in MyViewModel will not dependent on the Context,
    which means no instrumental tests are needed. You can test it with
    plain Kotlin/Java tests.

  • I know that you might not want to test it, but one of the good
    results of testing is that it makes the code better. If you make
    testable code it will be better even if you do not test it.
    And in
    this case, you are not making heavy ViewModels which is a bad idea.

  • Also, I am suggesting you to use Dagger-Hilt if you are not using it
    already - @Inject

Pass Application or ApplicationContext to ViewModel?

The Application object is literally the same object as the object returned by getApplicationContext().

If you're using an AndroidViewModel with the default factory, you'll get an Application object suitable to use as a Context (as Application extends Context).



Related Topics



Leave a reply



Submit