https://kotlinlang.org logo
#android
Title
# android
e

Ellen Spertus

03/10/2020, 5:27 PM
I’d like to start using
ViewModel
for my state. Could anyone advise me how to adapt the https://developer.android.com/topic/libraries/architecture/viewmodel example to support the case where an argument needs to be passed into
getUsers()
and through to
loadUsers()
for it to do its job?
Copy code
class MyViewModel : ViewModel() {
    private val users: MutableLiveData<List<User>> by lazy {
        MutableLiveData().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<User>> {
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}
I could store the information in an instance variable from
getUsers()
and retrieve it from
loadUsers()
, but that doesn’t seem very nice. What I need to pass in is a
Context
(to access assets and the package manager). I don’t cache the Context.
I found this solution to accessing a
Context
from a
ViewModel
. Is this the way to go? https://stackoverflow.com/a/56490520/631051
a

Alan Donizete

03/10/2020, 5:47 PM
I don't think this is a good idea, at least for me, your viewModel shouldn't know the context, only the business rules and the state of the app, the view can handle the assets depending on the state
if you need the context to access the data layer, you could use dependency injection to deal with it (I strongly recommend koin)
e

Ellen Spertus

03/10/2020, 5:48 PM
Thank you, @Alan Donizete. How should I store data that should persist through the lifetime of the application even if
MainActivity
gets destroyed?
Would it be any better to pass in the assets and package manager rather than the context, or is that just as bad?
a

Adam Powell

03/11/2020, 2:02 AM
what phase of the process do you need the
Context
for? If you can keep the ViewModel working only in terms of
Context
-insensitive data you can mix in the additional asset loading at the last mile with something like a
.map {}
of the users LiveData from your example
a

Anastasia Finogenova

03/11/2020, 2:17 AM
You can inject application class for access to context and assets etc. It will not impact your testability as your can always mock the Application class. Passing application context is pretty much safe vs activity context that will leak if it is retained somewhere in your Utils/Helper or in the repo layer.
a

Adam Powell

03/11/2020, 2:21 AM
The application context often won't have the correct
Configuration
set up, so depending what kind of resources or assets you're loading, it's an easy way to get the wrong thing
if you're just looking for the package-level data like filesystem paths, sure it'll work just swell, and you can use the
AndroidViewModel
base class to get it without additional injection if you're not already using a DI system
a

Anastasia Finogenova

03/11/2020, 2:23 AM
I know you mentioned you wanna follow that example. But you can just have that users live data created as a normal variable of MutableLiveData type and update it when the users are loaded inside loadUsers() Some pseudo code in the VM: val users = MutableLiveData<List<User>>() fun loadUsers(myParam: Param) { viewModelScope.launch(Dispatcher.IO) { repository.loadUsers(myParam)?.let{ users.postValue(it) } } } Provided you are using coroutines and your repo returns List<User>
For caching across app restarts....Room, SharedPreferences
😂 1
2 Views