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 ViewModels 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 ViewModelso:
@Module
abstract class ActivityViewModelModule {
@MainScope
@Binds
@IntoMap
@ViewModelKey(ActivityViewModel::class)
abstract fun bindActivityViewModel(viewModel: ActivityViewModel): ViewModel
}
Ich benutze @ContributesAndroidInjectorfür mein Fragment Folgendes:
@Module
abstract class MainFragmentBuildersModule {
@ContributesAndroidInjector
abstract fun contributeActivityFragment(): ActivityFragment
}
Und ich füge diese Module meiner MainActivityUnterkomponente 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 DaggerFragmentund spritze ViewModelProviderFactoryso:
@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 keywird 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
masterZweig 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_fineBranch nicht verwenden werden. Warum brauchen Sie den Umfang?