Reputation: 206
I have a problem with New Architecture components in Kotlin, when I create ViewModel component in recomended way (in onCreate() method) the result is as suposed:
Here is the way i create this
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list)
val arrayMap = ArrayMap<Class<out ViewModel>, ViewModel>()
arrayMap.put(ListViewModel::class.java, ListViewModel(webApi, repoDao))
val factory = ViewModelFactory(arrayMap)
listViewModel = ViewModelProviders.of(this, factory).get(ListViewModel::class.java)
listViewModel.items.observe({ this.lifecycle }) {
Toast.makeText(this, it?.joinToString { it + " " } ?: "null", Toast.LENGTH_SHORT).show()
}
But when I have used Dagger for inject ListViewModel I got new instance of ListViewModel every time Activity was recreated. Here is a code of Dagger ListActivityModel.
@Module @ListActivityScopeclass ListActivityModule {
@Provides
@ListActivityScope
fun provideListViewModel(webApi: WebApi, repoDao: RepoDao, listActivity: ListActivity): ListViewModel {
val arrayMap = ArrayMap<Class<out ViewModel>, ViewModel>()
arrayMap.put(ListViewModel::class.java, ListViewModel(webApi, repoDao))
val factory = ViewModelFactory(arrayMap)
val result = ViewModelProviders.of(listActivity, factory).get(ListViewModel::class.java)
return result
}
} Then ListActivity onCreate() method looks like:
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list)
listViewModel.items.observe({ this.lifecycle }) {
Toast.makeText(this, it?.joinToString { it + " " } ?: "null", Toast.LENGTH_SHORT).show()
}
}
And there is what I have notice after logging:
D/ListActivity: ---> onCreate() ListActivity: = [com.example.dom.app.new_arch.ListActivity@a0f2778]
D/ListActivity: ---> onCreate() listViewModel: = [com.example.dom.app.new_arch.ListViewModel@54a8e51]
//Activity orientation changes
E/ViewModelStores: Failed to save a ViewModel for com.example.dom.app.new_arch.ListActivity@a0f2778
D/ListActivity: ---> onCreate() ListActivity: = [com.example.dom.app.new_arch.ListActivity@6813433]
D/ListActivity: ---> onCreate() listViewModel: = [com.example.dom.app.new_arch.ListViewModel@55cf3f0]
The error I have received :
ViewModelStores: Failed to save a ViewModel for
comes from Android class HolderFragment with package android.arch.lifecycle.
There is something what I missed working with Dagger and new arch components?
Upvotes: 1
Views: 472
Reputation: 141
The issue has to do with the order of dagger injection and activity creation. The view model implementation relies on a non-visual fragment for identity. By injecting the viewModelProvider before the activity has completed onCreate it is unable to complete this association.
Since super.onCreate
does not likely depend on things you are injecting try injecting after the call to super.onCreate
and you should be fine.
I had this exact same issue and solved it by this change in order.
Specifically from your code instead of:
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list)
go with:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidInjection.inject(this)
setContentView(R.layout.activity_list)
JP
Upvotes: 1
Reputation: 5503
I don't use AndroidInjection.inject()
because it creates a new Dagger component. I create an Dagger Component in the Application class and I use that component instance to call inject in all other places of the app. This way your singletons are initialized only one time.
Upvotes: 0
Reputation: 315
The way I do this is by only providing the ViewModelFactory
using Dagger. Then it gets injected in the activity and you call ViewModelProviders.of(listActivity, factory).get(ListViewModel::class.java)
from there. The reason your approach doesn't work is that AndroidInjection.inject()
will create the ViewModel before onCreate, which leads to undefined behavior.
Also see: https://github.com/googlesamples/android-architecture-components/issues/202
Upvotes: 0