Estoy tratando de agregar Dagger 2 a mi proyecto. Pude inyectar ViewModels (componente de Arquitectura AndroidX) para mis fragmentos.
Tengo un ViewPager que tiene 2 instancias del mismo fragmento (solo un cambio menor para cada pestaña) y en cada pestaña, estoy observando una LiveData
actualización sobre el cambio de datos (desde la API).
El problema es que cuando llega la respuesta de la API y la actualiza LiveData
, los mismos datos en el fragmento actualmente visible se envían a los observadores en todas las pestañas. (Creo que esto es probablemente debido al alcance de la ViewModel
).
Así es como estoy observando mis datos:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
activityViewModel.expenseList.observe(this, Observer {
swipeToRefreshLayout.isRefreshing = false
viewAdapter.setData(it)
})
....
}
Estoy usando esta clase para proporcionar ViewModel
s:
class ViewModelProviderFactory @Inject constructor(creators: MutableMap<Class<out ViewModel?>?, Provider<ViewModel?>?>?) :
ViewModelProvider.Factory {
private val creators: MutableMap<Class<out ViewModel?>?, Provider<ViewModel?>?>? = creators
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
var creator: Provider<out ViewModel?>? = creators!![modelClass]
if (creator == null) { // if the viewmodel has not been created
// loop through the allowable keys (aka allowed classes with the @ViewModelKey)
for (entry in creators.entries) { // if it's allowed, set the Provider<ViewModel>
if (modelClass.isAssignableFrom(entry.key!!)) {
creator = entry.value
break
}
}
}
// if this is not one of the allowed keys, throw exception
requireNotNull(creator) { "unknown model class $modelClass" }
// return the Provider
return try {
creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
companion object {
private val TAG: String? = "ViewModelProviderFactor"
}
}
Estoy vinculando mi ViewModel
así:
@Module
abstract class ActivityViewModelModule {
@MainScope
@Binds
@IntoMap
@ViewModelKey(ActivityViewModel::class)
abstract fun bindActivityViewModel(viewModel: ActivityViewModel): ViewModel
}
Estoy usando @ContributesAndroidInjector
para mi fragmento así:
@Module
abstract class MainFragmentBuildersModule {
@ContributesAndroidInjector
abstract fun contributeActivityFragment(): ActivityFragment
}
Y estoy agregando estos módulos a mi MainActivity
subcomponente así:
@Module
abstract class ActivityBuilderModule {
...
@ContributesAndroidInjector(
modules = [MainViewModelModule::class, ActivityViewModelModule::class,
AuthModule::class, MainFragmentBuildersModule::class]
)
abstract fun contributeMainActivity(): MainActivity
}
Aquí está mi AppComponent
:
@Singleton
@Component(
modules =
[AndroidSupportInjectionModule::class,
ActivityBuilderModule::class,
ViewModelFactoryModule::class,
AppModule::class]
)
interface AppComponent : AndroidInjector<SpenmoApplication> {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
}
Estoy extendiendo DaggerFragment
e inyectando ViewModelProviderFactory
así:
@Inject
lateinit var viewModelFactory: ViewModelProviderFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
....
activityViewModel =
ViewModelProviders.of(this, viewModelFactory).get(key, ActivityViewModel::class.java)
activityViewModel.restartFetch(hasReceipt)
}
El key
será diferente para ambos fragmentos.
¿Cómo puedo asegurarme de que solo el observador del fragmento actual se esté actualizando?
EDITAR 1 ->
He agregado un proyecto de muestra con el error. Parece que el problema ocurre solo cuando se agrega un ámbito personalizado. Consulte el proyecto de muestra aquí: enlace de Github
master
Branch tiene la aplicación con el problema. Si actualiza cualquier pestaña (deslice para actualizar), el valor actualizado se refleja en ambas pestañas. Esto solo sucede cuando le agrego un alcance personalizado ( @MainScope
).
working_fine
Branch tiene la misma aplicación sin alcance personalizado y funciona bien.
Avíseme si la pregunta no está clara.
working_fine
rama? ¿Por qué necesitas el alcance?