Ich versuche, Dagger 2 zu meinem Projekt hinzuzufügen. Ich konnte ViewModels (AndroidX Architecture-Komponente) für meine Fragmente einfügen.
Ich habe einen ViewPager mit 2 Instanzen desselben Fragments (nur eine geringfügige Änderung für jede Registerkarte) und in jeder Registerkarte beobachte ich eine LiveData
, um über Datenänderungen (von der API) aktualisiert zu werden.
Das Problem ist, dass, wenn die API-Antwort kommt und die aktualisiert LiveData
, dieselben Daten im aktuell sichtbaren Fragment an Beobachter auf allen Registerkarten gesendet werden. (Ich denke, das liegt wahrscheinlich am Umfang der ViewModel
).
So beobachte ich meine Daten:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
activityViewModel.expenseList.observe(this, Observer {
swipeToRefreshLayout.isRefreshing = false
viewAdapter.setData(it)
})
....
}
Ich benutze diese Klasse, um ViewModel
s bereitzustellen :
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"
}
}
Ich binde meine ViewModel
so:
@Module
abstract class ActivityViewModelModule {
@MainScope
@Binds
@IntoMap
@ViewModelKey(ActivityViewModel::class)
abstract fun bindActivityViewModel(viewModel: ActivityViewModel): ViewModel
}
Ich benutze @ContributesAndroidInjector
für mein Fragment Folgendes:
@Module
abstract class MainFragmentBuildersModule {
@ContributesAndroidInjector
abstract fun contributeActivityFragment(): ActivityFragment
}
Und ich füge diese Module meiner MainActivity
Unterkomponente folgendermaßen hinzu:
@Module
abstract class ActivityBuilderModule {
...
@ContributesAndroidInjector(
modules = [MainViewModelModule::class, ActivityViewModelModule::class,
AuthModule::class, MainFragmentBuildersModule::class]
)
abstract fun contributeMainActivity(): MainActivity
}
Hier ist mein 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
}
}
Ich dehne DaggerFragment
und spritze ViewModelProviderFactory
so:
@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)
}
Das key
wird für beide Fragmente unterschiedlich sein.
Wie kann ich sicherstellen, dass nur der Beobachter des aktuellen Fragments aktualisiert wird?
BEARBEITEN 1 ->
Ich habe ein Beispielprojekt mit dem Fehler hinzugefügt. Das Problem tritt anscheinend nur auf, wenn ein benutzerdefinierter Bereich hinzugefügt wird. Bitte sehen Sie sich das Beispielprojekt hier an: Github-Link
master
Zweig hat die App mit dem Problem. Wenn Sie eine Registerkarte aktualisieren (zum Aktualisieren wischen), wird der aktualisierte Wert in beiden Registerkarten angezeigt. Dies geschieht nur, wenn ich einen benutzerdefinierten Bereich hinzufüge ( @MainScope
).
working_fine
Branch hat die gleiche App ohne benutzerdefinierten Bereich und funktioniert einwandfrei.
Bitte lassen Sie mich wissen, wenn die Frage nicht klar ist.
working_fine
Branch nicht verwenden werden. Warum brauchen Sie den Umfang?