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
How to Open Draw Overlay Permission Popup in Miui
How to Execute Code When Application Is Closing
How to Set Button Click Effect in Android
Pdf Not Open in Webview from Url
How to Remove the Black Bar Appearing At the Bottom
How to Remove Bottom Navigation View and Toolbar in Some Fragments If Using Navigation Controller
Retrieve Stored Image from Firebase Storage
Setcontentview(R.Layout.Main); Gives Error from Start
How to Get the Result of Onpostexecute() to Main Activity Because Asynctask Is a Separate Class
Android Set Height and Width of Custom View Programmatically
How to Avoid the Frame Layout Is Pushed Up When the Soft Keyboard Appears
React Native: Determine Number of Lines of Text Component
How to Fix Attempt to Invoke Interface Method on a Null Object Reference
How to Center Items of a Recyclerview
Architecture Components: Observer Keep Observing Even After Removing It on Ondestroy