У меня есть действие с ViewPager
, которое отображает те же данные либо в виде карты (страница 0), либо в списке (страница 1).Происходит некоторая фильтрация, поэтому я подумал, что эта фильтрация может быть применена в упражнении (которое содержит представления) и передана в ViewModel
, который через LiveData
обновит оба Fragments
(просмотр карты и список)
Теория звучит хорошо, но когда я ее реализую, мой компонент всегда вводит новые экземпляры для действия и обоих фрагментов.Я нашел, напечатав следующие строки:
05-31 13:36:16.832 16091-16091/W/DashboardActivity: Hello com.myapp.sample.ui.dashboard.DashboardViewModel@b8bb537 from com.myapp.sample.ui.dashboard.DashboardActivity@899a9f6
05-31 13:36:17.133 16091-16091/W/MyPicksMapFragment: Hello com.myapp.sample.ui.dashboard.DashboardViewModel@59e2119 from MapFragment{72070f4 #1 id=0x7f090137 android:switcher:2131296567:0}
05-31 13:36:18.139 16091-16091/W/MyPicksListFragment: Hello com.myapp.sample.ui.dashboard.DashboardViewModel@58a33fb from ListFragment{2be0446 #2 id=0x7f090137 android:switcher:2131296567:1}
Эта строка подтверждает то же самое Component
:
05-31 13:47:49.509 18411-18411/com.myapp.sample.dev.debug E/DashboardActivity: Saying hello from component com.myapp.sample.di.application.DaggerApplicationComponent$ControllerComponentImpl@4ccc864 within com.myapp.sample.ui.dashboard.DashboardActivity@57a81f7
05-31 13:47:50.350 18411-18411/com.myapp.sample.dev.debug E/MyPicksMapFragment: Saying hello from component com.myapp.sample.di.application.DaggerApplicationComponent$ControllerComponentImpl@4ccc864 within MyPicksMapFragment{3443332 #1 id=0x7f090137 android:switcher:2131296567:0}
05-31 13:47:51.194 18411-18411/com.myapp.sample.dev.debug E/MyPicksListFragment: Saying hello from component com.myapp.sample.di.application.DaggerApplicationComponent$ControllerComponentImpl@4ccc864 within MyPicksListFragment{e520996 #2 id=0x7f090137 android:switcher:2131296567:1}
Это моя деятельность:
class DashboardActivity : BaseActivity<DashboardViewModel>() {
override fun inject() {
Timber.e("Saying hello from component $component within $this")
component.inject(this)
}
}
Базовая активность:
abstract class BaseActivity<E : ViewModel> : AppCompatActivity() {
val component by lazy { (application as SoulpicksApp)
.applicationComponent
.plus(
ControllerModule(this)
)
}
@Inject
protected lateinit var viewModel: E
}
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
inject()
}
Один из фрагментов:
class MyPicksListFragment : BaseFragment<DashboardViewModel>() {
override fun inject() {
var component = (activity as DashboardActivity).component
Timber.e("Saying hello from component $component within $this")
component.inject(this)
}
}
Базовый фрагмент:
abstract class BaseFragment<E : ViewModel> : Fragment() {
@Inject
protected lateinit var viewModel: E
@CallSuper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
inject()
}
}
Компонент приложения:
@Module(includes = [ViewModelModule::class])
class ApplicationModule(val application: Application) {
(...)
}
ViewModelFactory:
class ViewModelFactory @Inject constructor(
private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T = viewModels[modelClass]?.get() as T
}
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
ViewModelModule:
@Module
abstract class ViewModelModule {
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}
@Binds
@IntoMap
@ViewModelKey(DashboardViewModel::class)
internal abstract fun dashboardViewModel(viewModel: DashboardViewModel): ViewModel
}
Компонент контроллера:
@Module(includes = [ViewContainerModule::class])
class ControllerModule(val activity: FragmentActivity) {
@Provides
@ControllerScope
fun context(): Context = activity
@Provides
@ControllerScope
fun activity() = activity
@Provides
@ControllerScope
fun layoutInflater() = activity.layoutInflater
@Provides
@ControllerScope
fun fragmentManager(): android.support.v4.app.FragmentManager = activity.supportFragmentManager
@Provides
@ControllerScope
fun smsAuthManager(context: Context) = SmsAuthManager(context)
@Provides
@ControllerScope
fun provideConnectivityManager(context: Context): ConnectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
@Provides
@ControllerScope
fun provideNetworkInteractor(networkInteractor: NetworkInteractorImpl): NetworkInteractor = networkInteractor
@Provides
@ControllerScope
fun provideLocationManager(context: Context): RxLocationManager = RxLocationManagerImpl(context)
@Provides
@ControllerScope
fun provideNavigationController(activity: FragmentActivity) = NavigationController(activity)
}