Я намагаюся додати Dagger 2 до свого проекту. Мені вдалося ввести ViewModels (компонент архітектури AndroidX) для своїх фрагментів.
У мене є ViewPager, який має два екземпляри одного фрагмента (лише незначні зміни для кожної вкладки), і в кожній вкладці я спостерігаю за LiveData
оновленням змін даних (від API).
Проблема полягає в тому, що коли приходить відповідь api та оновлюється LiveData
, ті самі дані у видимому на сьогодні фрагменті надсилаються спостерігачам у всі вкладки. (Я думаю, це, мабуть, через сферу дії ViewModel
).
Ось як я спостерігаю за своїми даними:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
activityViewModel.expenseList.observe(this, Observer {
swipeToRefreshLayout.isRefreshing = false
viewAdapter.setData(it)
})
....
}
Я використовую цей клас для надання 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"
}
}
Я зобов’язую ViewModel
так:
@Module
abstract class ActivityViewModelModule {
@MainScope
@Binds
@IntoMap
@ViewModelKey(ActivityViewModel::class)
abstract fun bindActivityViewModel(viewModel: ActivityViewModel): ViewModel
}
Я використовую @ContributesAndroidInjector
для цього фрагмент так:
@Module
abstract class MainFragmentBuildersModule {
@ContributesAndroidInjector
abstract fun contributeActivityFragment(): ActivityFragment
}
І я додаю ці модулі до свого MainActivity
підкомпонента так:
@Module
abstract class ActivityBuilderModule {
...
@ContributesAndroidInjector(
modules = [MainViewModelModule::class, ActivityViewModelModule::class,
AuthModule::class, MainFragmentBuildersModule::class]
)
abstract fun contributeMainActivity(): MainActivity
}
Ось мій 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
}
}
Я розширюю DaggerFragment
та ввожу ViewModelProviderFactory
так:
@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)
}
key
буде відрізнятися для обох фрагментів.
Як я можу переконатися, що лише спостерігач поточного фрагмента оновлюється.
РЕДАКТ 1 ->
Я додав зразок проекту з помилкою. Здається, що проблема виникає лише тоді, коли додається спеціальна область. Перевірте зразок проекту тут: посилання Github
master
відділення має додаток із проблемою. Якщо ви оновите будь-яку вкладку (проведіть пальцем, щоб оновити), оновлене значення відображається на обох вкладках. Це відбувається лише тоді, коли я додаю до нього власну область ( @MainScope
).
working_fine
відділення має те саме додаток, що не користується сферою застосування, і він працює добре.
Будь ласка, повідомте мене, якщо питання не ясно.
working_fine
філії? Для чого потрібна область застосування?