I have this
class ForceUpdateViewModelFactory(
private val mApplication: Application,
private val mForceType: ForceUpdateType
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
require(modelClass == ForceUpdateViewModel::class.java) {
"Unsupported model class: $modelClass"
}
return ForceUpdateViewModel(mApplication, mForceType) as T
}
}
and I use it in a Fragment.
class ForceUpdateViewModel(
application: Application,
forceType: ForceUpdateType
) :
AndroidViewModel(application) {
private val mUpdatePickataleEvent = LiveEvent<Void>()
private val mMaybeLaterEvent = LiveEvent<Void>()
val maybeLaterBtnVisibility: LiveData<Int> = getApplication<App>().configManager
.effectiveConfigurationSingle
.map { config ->
if (forceType == ForceUpdateType.HARD) View.VISIBLE else View.GONE
}.toObservable().asLiveData()
fun getUpdatePickataleEvent(): LiveData<Void> = mUpdatePickataleEvent
fun getMaybeLaterEvent(): LiveData<Void> = mMaybeLaterEvent
fun onUpdatePickataleBtnClick() {
mUpdatePickataleEvent.raise()
}
fun onMaybeLaterBtnClick() {
mMaybeLaterEvent.raise()
}
}
The problem is that I would like to listen for the getMaybeLaterEvent in the parent Activity, but that Activity is in Java. I have no idea how to share the view model with the Activity in this case.
Normally, I THINK, I'd do it by using val sharedViewModel: MyViewModel by activityViewModels() or something of the sorts, but i have no idea how to do that in Java.
When you use by activityViewModels() in a Fragment, that's equivalent to using by viewModels() in an Activity. It's a ViewModel scoped to the associated Activity lifecycle either way.
Since you want a ViewModel reference in your Activity and you want to keep it Java, you can't use a property delegate. This would be the equivalent of by viewModels { ForceUpdateViewModelFactory() } in the Activity:
private ForceUpdateViewModelFactory viewModel;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
viewModel = new ViewModelProvider(this, new ForceUpdateViewModelFactory())
.get(ForceUpdateViewModel.class);
//...
}
I'm trying to show a Snackbar in MainFragment when I click a button inside DialogFragment.
When I call the send event function (in ViewModel) from the dialog class nothing happens. I don't know what I'm doing wrong but other functions which do similar things in the MainFragment work just fine.
In ViewModel, the clearInput() function which clears the editText in MainFragment works but onEditNoteClicked() doesn't work and nothing happens when I call it.
NoteOptionsDialog class:
#AndroidEntryPoint
class NoteOptionsDialog : BottomSheetDialogFragment() {
private val viewModel: NotesViewModel by viewModels()
private fun setupClickListeners(view: View) {
view.bottom_options_edit.setOnClickListener {
viewModel.onEditNoteClicked()
dismiss()
}
}
NotesViewModel class:
#HiltViewModel
class NotesViewModel #Inject constructor(
private val noteDao: NoteDao,
private val preferencesManager: PreferencesManager,
private val state: SavedStateHandle
) : ViewModel() {
private val notesEventChannel = Channel<NotesEvent>()
val notesEvent = notesEventChannel.receiveAsFlow()
fun onSaveNoteClick() {
val newNote = Note(noteText = noteText, noteLabelId = labelId.value)
createNote(newNote)
}
private fun createNote(newNote: Note) = viewModelScope.launch {
noteDao.insertNote(newNote)
clearInput()
}
private fun clearInput() = viewModelScope.launch {
notesEventChannel.send(NotesEvent.ClearEditText)
}
fun onEditNoteClicked() = viewModelScope.launch {
notesEventChannel.send(NotesEvent.ShowToast)
}
fun onNoteSelected(note: Note, view: View) = viewModelScope.launch {
notesEventChannel.send(NotesEvent.ShowBottomSheetDialog(note, view))
}
sealed class NotesEvent {
object ClearEditText : NotesEvent()
object ShowToast : NotesEvent()
data class ShowBottomSheetDialog(val note: Note, val view: View) : NotesEvent()
}
NotesFragment class:
#AndroidEntryPoint
class NotesFragment : Fragment(R.layout.fragment_home), NotesAdapter.OnNoteItemClickListener,
LabelsAdapter.OnLabelItemClickListener {
private val viewModel: NotesViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?){
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.notesEvent.collect { event ->
when (event) {
is NotesViewModel.NotesEvent.ShowBottomSheetDialog -> {
NoteOptionsDialog().show(childFragmentManager, null)
}
is NotesViewModel.NotesEvent.ClearEditText -> {
et_home_note.text.clear()
}
is NotesViewModel.NotesEvent.ShowToast -> {
Snackbar.make(requireView(), "Snack!", Snackbar.LENGTH_LONG).show()
}
}
Found the solution. For fragments, I should have used by activityViewModels() instead of by viewModels()
private val viewModel: NotesViewModel by activityViewModels()
initialize viewmodel like below in fragments for sharing same instance
private val viewModel: NotesViewModel by activityViewModels()
I develop app with MVVM pattern. I want save UI when user rotate screen.
MyViewModel.kt
class MyViewModel(val repository: SomeRepository,
state : SavedStateHandle) : ViewModel() {
private val savedStateHandle = state
companion object {
const val KEY = "KEY"
}
fun saveCityId(cityId: String) {
savedStateHandle.set(CITY_KEY, cityId)
}
fun getCityId(): String? {
return savedStateHandle.get(CITY_KEY)
}
}
ViewModelFactory.kt
#Suppress("UNCHECKED_CAST")
class ViewModelFactory(
private val repository: SomeRepository,
private val state: SavedStateHandle
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MyViewModel(repository,state) as T
}
}
I call it in MainActivity
MainActivity.kt
class MainActivity: AppCompatActivity(), KodeinAware {
private val factory: ViewModelFactoryby instance()
override val kodein by kodein()
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
cityId = intent.getStringExtra("cityId") ?: viewModel.getCityId()
if (cityId != null) {
viewModel.saveCityId(cityId!!)
viewModel.getCurrentWeather(cityId!!)
}
}
Here i inject dependencies
Application.kt
class ForecastApplication: Application(), KodeinAware {
override val kodein = Kodein.lazy {
import(androidXModule(this#ForecastApplication))
bind<SomeApi>() with singleton {
Retrofit.create()
}
bind<WeatherRepository>() with singleton {
WeatherRepository(instance())
}
bind() from provider {
WeatherViewModelFactory(
instance(), instance()
)
}
}
}
And i have this error
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simpleforecast/com.example.simpleapp.UI.Cities.Activity}:org.kodein.di.Kodein$NotFoundException: No binding found for bind<SavedStateHandle>()
with ?<Activity>().? { ? }
How shoud i build ViewModelFactory and inject Saved State module for ViewModel?
SavedStateHandle is parameter which cannot be bound to the DI graph, because it's retrieved from Fragment (or Activity), therefore you need to do several steps in order to make it work:
1) DI viewmodel definition - since you have custom parameter, you need to use from factory:
bind() from factory { handle: SavedStateHandle ->
WeatherViewModel(
state = handle,
repository = instance()
)
}
2) ViewModel Factory - you need to inherit from AbstractSavedStateViewModelFactory
val vmFactory = object : AbstractSavedStateViewModelFactory(this, arguments) {
override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
val vmFactory: ((SavedStateHandle) -> WeatherViewModel) = kodein.direct.factory()
return vmFactory(handle) as T
}
}
Inside of the create method you'd retrieve the factory from your DI graph (from step 1).
3) You retrieve ViewModel with the specified factory:
lateinit var vm : WeatherViewModel
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
vm = ViewModelProvider(this, vmFactory)[WeatherViewModel::class.java]
}
or android KTX way:
val vm : WeatherViewModel by viewModels { vmFactory }
I'm trying to use the new liveData builder referenced here to retrieve my data, then transform it into view models. However, my repository code isn't being invoked (at least I'm not able to see it being triggered when I use my debugger). Am I not supposed to use two liveData{ ... } builders? (one in my repository, one in my view model)?
class MyRepository #Inject constructor() : Repository {
override fun getMyContentLiveData(params: MyParams): LiveData<MyContent> =
liveData {
val myContent = networkRequest(params) // send network request with params
emit(myContent)
}
}
class MyViewModel #Inject constructor(
private val repository: MyRepository
) : ViewModel() {
val viewModelList = liveData(Dispatchers.IO) {
val contentLiveData = repository.getContentLiveData(keyParams)
val viewModelLiveData = contentToViewModels(contentLiveData)
emit(viewModelLiveData)
}
private fun contentToViewModels(contentLiveData: LiveData<MyContent>): LiveData<List<ViewModel>> {
return Transformations.map(contentLiveData) { content ->
//perform some transformation and return List<ViewModel>
}
}
}
class MyFragment : Fragment() {
#Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
val myViewModel: MyViewModel by lazy {
ViewModelProviders.of(this, viewModelFactory).get(MyViewModel::class.java)
}
lateinit var params: MyParams
override fun onAttach(context: Context) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
myViewModel.params = params
myViewModel.viewModelList.observe(this, Observer {
onListChanged(it)
})
}
You could try with the emitSource:
val viewModelList = liveData(Dispatchers.IO) {
emitSource(
repository.getContentLiveData(keyParams).map {
contentToViewModels(it)
}
}
Is there a way to pass additional argument to my custom AndroidViewModel constructor except Application context.
Example:
public class MyViewModel extends AndroidViewModel {
private final LiveData<List<MyObject>> myObjectList;
private AppDatabase appDatabase;
public MyViewModel(Application application, String param) {
super(application);
appDatabase = AppDatabase.getDatabase(this.getApplication());
myObjectList = appDatabase.myOjectModel().getMyObjectByParam(param);
}
}
And when I want to user my custom ViewModel class I use this code in my fragment:
MyViewModel myViewModel = ViewModelProvider.of(this).get(MyViewModel.class)
So I don't know how to pass additional argument String param into my custom ViewModel. I can only pass Application context, but not additional arguments. I would really appreciate any help. Thank you.
Edit: I've added some code. I hope it's better now.
You need to have a factory class for your ViewModel.
public class MyViewModelFactory implements ViewModelProvider.Factory {
private Application mApplication;
private String mParam;
public MyViewModelFactory(Application application, String param) {
mApplication = application;
mParam = param;
}
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
return (T) new MyViewModel(mApplication, mParam);
}
}
And when instantiating the view model, you do like this:
MyViewModel myViewModel = ViewModelProvider(this, new MyViewModelFactory(this.getApplication(), "my awesome param")).get(MyViewModel.class);
For kotlin, you may use delegated property:
val viewModel: MyViewModel by viewModels { MyViewModelFactory(getApplication(), "my awesome param") }
There's also another new option - to implement HasDefaultViewModelProviderFactory and override getDefaultViewModelProviderFactory() with the instantiation of your factory and then you would call ViewModelProvider(this) or by viewModels() without the factory.
Implement with Dependency Injection
This is more advanced and better for production code.
Dagger2, Square's AssistedInject offers a production-ready implementation for ViewModels that can inject necessary components such as a repository that handles network and database requests. It also allows for the manual injection of arguments/parameters in the activity/fragment. Here's a concise outline of the steps to implement with code Gists based on Gabor Varadi's detailed post, Dagger Tips.
Dagger Hilt, is the next generation solution, in alpha as of 7/12/20, offering the same use case with a simpler setup once the library is in release status.
Implement with Lifecycle 2.2.0 in Kotlin
Passing Arguments/Parameters
// Override ViewModelProvider.NewInstanceFactory to create the ViewModel (VM).
class SomeViewModelFactory(private val someString: String): ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T = SomeViewModel(someString) as T
}
class SomeViewModel(private val someString: String) : ViewModel() {
init {
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
}
}
class Fragment: Fragment() {
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory("someString") }
}
Enabling SavedState with Arguments/Parameters
class SomeViewModelFactory(
private val owner: SavedStateRegistryOwner,
private val someString: String) : AbstractSavedStateViewModelFactory(owner, null) {
override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, state: SavedStateHandle) =
SomeViewModel(state, someString) as T
}
class SomeViewModel(private val state: SavedStateHandle, private val someString: String) : ViewModel() {
val feedPosition = state.get<Int>(FEED_POSITION_KEY).let { position ->
if (position == null) 0 else position
}
init {
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
}
fun saveFeedPosition(position: Int) {
state.set(FEED_POSITION_KEY, position)
}
}
class Fragment: Fragment() {
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory(this, "someString") }
private var feedPosition: Int = 0
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
someViewModel.saveFeedPosition((contentRecyclerView.layoutManager as LinearLayoutManager)
.findFirstVisibleItemPosition())
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
feedPosition = someViewModel.feedPosition
}
}
For one factory shared between multiple different view models I'd extend mlyko's answer like this:
public class MyViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private Application mApplication;
private Object[] mParams;
public MyViewModelFactory(Application application, Object... params) {
mApplication = application;
mParams = params;
}
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (modelClass == ViewModel1.class) {
return (T) new ViewModel1(mApplication, (String) mParams[0]);
} else if (modelClass == ViewModel2.class) {
return (T) new ViewModel2(mApplication, (Integer) mParams[0]);
} else if (modelClass == ViewModel3.class) {
return (T) new ViewModel3(mApplication, (Integer) mParams[0], (String) mParams[1]);
} else {
return super.create(modelClass);
}
}
}
And instantiating view models:
ViewModel1 vm1 = ViewModelProviders.of(this, new MyViewModelFactory(getApplication(), "something")).get(ViewModel1.class);
ViewModel2 vm2 = ViewModelProviders.of(this, new MyViewModelFactory(getApplication(), 123)).get(ViewModel2.class);
ViewModel3 vm3 = ViewModelProviders.of(this, new MyViewModelFactory(getApplication(), 123, "something")).get(ViewModel3.class);
With different view models having different constructors.
Based on #vilpe89 the above Kotlin solution for AndroidViewModel cases
class ExtraParamsViewModelFactory(
private val application: Application,
private val myExtraParam: String
): ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
SomeViewModel(application, myExtraParam) as T
}
Then a fragment can initiate the viewModel as
class SomeFragment : Fragment() {
// ...
private val myViewModel: SomeViewModel by viewModels {
ExtraParamsViewModelFactory(this.requireActivity().application, "some string value")
}
// ...
}
And then the actual ViewModel class
class SomeViewModel(application: Application, val myExtraParam:String) : AndroidViewModel(application) {
// ...
}
Or in some suitable method ...
override fun onActivityCreated(...){
// ...
val myViewModel = ViewModelProvider(this, ExtraParamsViewModelFactory(this.requireActivity().application, "some string value")).get(SomeViewModel::class.java)
// ...
}
I made it a class in which the already created object is passed.
private Map<String, ViewModel> viewModelMap;
public ViewModelFactory() {
this.viewModelMap = new HashMap<>();
}
public void add(ViewModel viewModel) {
viewModelMap.put(viewModel.getClass().getCanonicalName(), viewModel);
}
#NonNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
for (Map.Entry<String, ViewModel> viewModel : viewModelMap.entrySet()) {
if (viewModel.getKey().equals(modelClass.getCanonicalName())) {
return (T) viewModel.getValue();
}
}
return null;
}
And then
ViewModelFactory viewModelFactory = new ViewModelFactory();
viewModelFactory.add(new SampleViewModel(arg1, arg2));
SampleViewModel sampleViewModel = ViewModelProviders.of(this, viewModelFactory).get(SampleViewModel.class);
The proper way is to use a dependency injection framework such as Dagger hilt. If not using a DI framework, then do it with ViewModelFactory.
With Dagger Hilt:
A ViewModel with parameters
#HiltViewModel
class MyViewModel #Inject constructor(
private val myRepository: MyRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() { ... }
A Repository
class MyRepository #Inject constructor(
private val myRemoteDataSource: MyDataSource,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) { ... }
A Module for providing the dependencies/parameters so they can be injected into repositories and ViewModels.
#InstallIn(ViewModelComponent::class)
#Module
object MyProvideModule {
#Provides
fun provideMyDataSource(#ApplicationContext context: Context): MyDataSource {
//code to create MyDataSource...
return MyDataSource(context)
}
#Provides
fun provideCoroutineDispatcher(): CoroutineDispatcher {
return Dispatchers.IO
}
}
A module for binding the repository
#Module
#InstallIn(ViewModelComponent::class)
interface RepositoryModules {
#Binds
fun provideMyRepository(repository: MyRepository): MyRepository
}
Initiating Dagger hilt with the application with the #HiltAndroidApp annotation.
#HiltAndroidApp
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
}
}
Getting the ViewModel in activities
#AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val myViewModel: MyViewModel by viewModels()
// Other code...
}
Getting the ViewModel in fragments
#AndroidEntryPoint
class MyFragment : Fragment() {
private val myViewModel: MyViewModel by activityViewModels()
// Other code...
}
With ViewModelFactory:
A ViewModel with parameter messageDataStore, where MessageDataStore is a DataStore class or it can be anything else that you want to pass into the ViewModel.
class MyViewModel(
private val messageDataStore: MessageDataStore,
): ViewModel() { ... }
The ViewModel factory class for creating ViewModels
/**
* Factory for all ViewModels.
*/
#Suppress("UNCHECKED_CAST")
class ViewModelFactory constructor(
private val messageDataStore: MessageDataStore,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = with(modelClass) {
when {
isAssignableFrom(MyViewModel::class.java) ->
MyViewModel(messageDataStore)
else ->
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
} as T
}
The application class for creating the dependencies/parameters
class MyApp : Application() {
val messageDataStore: MessageDataStore
get() = MessageDataStore.getInstance(this)
}
Extension functions for getting the factory class in activities and fragments, MyExt.kt
fun AppCompatActivity.getViewModelFactory(savedInstanceState: Bundle?): ViewModelFactory {
val messageDataStore = (applicationContext as MyApp).messageDataStore
return ViewModelFactory(messageDataStore, this, savedInstanceState)
}
fun Fragment.getViewModelFactory(savedInstanceState: Bundle?): ViewModelFactory {
val messageDataStore = (requireContext().applicationContext as MyApp).messageDataStore
return ViewModelFactory(messageDataStore, this.requireActivity(), savedInstanceState)
}
Getting the ViewMode in activities
class MainActivity : AppCompatActivity() {
private lateinit var myViewModel: MyViewModel
// Other code...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val vm by viewModels<MyViewModel> { getViewModelFactory(savedInstanceState) }
myViewModel = vm
// Other code...
}
}
Getting the ViewModel in Fragments.
class MyFragment : Fragment() {
private lateinit var myViewModel: MyViewModel
//Other code...
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val vm by activityViewModels<MyViewModel> { getViewModelFactory(savedInstanceState) }
myViewModel = vm
//Other code...
}
}
(KOTLIN) My solution uses little bit of Reflection.
Lets say you don't want to create the same looking Factory class every time you create new ViewModel class which needs some arguments. You can accomplish this via Reflection.
For example you would have two different Activities:
class Activity1 : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val args = Bundle().apply { putString("NAME_KEY", "Vilpe89") }
val viewModel = ViewModelProviders
.of(this, ViewModelWithArgumentsFactory(args))
.get(ViewModel1::class.java)
}
}
class Activity2 : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val args = Bundle().apply { putInt("AGE_KEY", 29) }
val viewModel = ViewModelProviders
.of(this, ViewModelWithArgumentsFactory(args))
.get(ViewModel2::class.java)
}
}
And ViewModels for those Activities:
class ViewModel1(private val args: Bundle) : ViewModel()
class ViewModel2(private val args: Bundle) : ViewModel()
Then the magic part, Factory class's implementation:
class ViewModelWithArgumentsFactory(private val args: Bundle) : NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
try {
val constructor: Constructor<T> = modelClass.getDeclaredConstructor(Bundle::class.java)
return constructor.newInstance(args)
} catch (e: Exception) {
Timber.e(e, "Could not create new instance of class %s", modelClass.canonicalName)
throw e
}
}
}
In Kotlin, since the caller of the ViewModel and the ViewModel itself run in different coroutines, it is more natural and convenient to pass data between them using kotlinx.coroutines.channels.Channel:
class NewViewModel : ViewModel() {
private val newData: MutableLiveData<Service.DataEntry?> by lazy {
MutableLiveData<Service.DataEntry?>().also {
viewModelScope.launch {
val channel = Service.ParamChannel // type Channel<Params>
val params = channel.receive()
it.value = Service.postSomething(params)
}
}
}
fun getData(): LiveData<Service.DataEntry?> {
return newData
}
}
// Calling code:
val model: NewViewModel by viewModels()
model.getData().observe(this) { newData ->
if (newData != null) {
...
}
else
{
...
}
}
runBlocking {
Service.ParamChannel.send(theParams)
}
This is part of working code which I anonymized for demo purposes.
I wrote a library that should make doing this more straightforward and way cleaner, no multibindings or factory boilerplate needed, while working seamlessly with ViewModel arguments that can be provided as dependencies by Dagger:
https://github.com/radutopor/ViewModelFactory
#ViewModelFactory
class UserViewModel(#Provided repository: Repository, userId: Int) : ViewModel() {
val greeting = MutableLiveData<String>()
init {
val user = repository.getUser(userId)
greeting.value = "Hello, $user.name"
}
}
In the view:
class UserActivity : AppCompatActivity() {
#Inject
lateinit var userViewModelFactory2: UserViewModelFactory2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
appComponent.inject(this)
val userId = intent.getIntExtra("USER_ID", -1)
val viewModel = ViewModelProviders.of(this, userViewModelFactory2.create(userId))
.get(UserViewModel::class.java)
viewModel.greeting.observe(this, Observer { greetingText ->
greetingTextView.text = greetingText
})
}
}
Why not do it like this:
public class MyViewModel extends AndroidViewModel {
private final LiveData<List<MyObject>> myObjectList;
private AppDatabase appDatabase;
private boolean initialized = false;
public MyViewModel(Application application) {
super(application);
}
public initialize(String param){
synchronized ("justInCase") {
if(! initialized){
initialized = true;
appDatabase = AppDatabase.getDatabase(this.getApplication());
myObjectList = appDatabase.myOjectModel().getMyObjectByParam(param);
}
}
}
}
and then use it like this in two steps:
MyViewModel myViewModel = ViewModelProvider.of(this).get(MyViewModel.class)
myViewModel.initialize(param)