Как вставить ViewModel в BottomSheetDialogFragment с помощью Dagger2?

Я вставляю свои зависимости в Действия и Фрагменты предпочтительным способом с помощью AndroidInjection.inject(this). У меня есть рекомендованный ViewmodelFactory для внедрения модели просмотра. Мои инъекции работают в Активностях и Фрагментах. Однако я столкнулся с проблемой с BottomSheetDialogFragment, потому что мне не разрешено указывать BottomSheetDialogFragment как this. Значит, мой @Inject lateinit var viewModelFactory: ViewModelFactory не инициализирован. Я считаю, что внедрение должно быть возможным, потому что BottomSheetDialogFragment должен быть подклассом класса Fragment, но похоже, что это не так. Я использую android.x, который, как мне кажется, тоже может вызвать проблемы. Возможно ли, что он еще не поддерживается Dagger?

Как мне реализовать инъекцию ViewModelFactory?

Обновление: когда я пытаюсь ввести фрагмент с AndroidInjection.inject(this), это невозможно с androidx.fragment.app.Fragment только с android.app.Fragement. Я расширяю свои фрагменты с помощью DaggerFragment, и они работают должным образом.


person codeme    schedule 28.11.2018    source источник


Ответы (1)


Вот как я добавил ViewModel в BottomSheetDialogFragment (). Прежде всего настройте Dagger в классе MyApp.

class MyApp : Application(), HasActivityInjector, HasSupportFragmentInjector {

@Inject
lateinit var activityInjector: DispatchingAndroidInjector<Activity>
@Inject
lateinit var supportFragmentInjector: DispatchingAndroidInjector<Fragment>

override fun onCreate() {
    super.onCreate()

    initDagger()
}

override fun activityInjector(): AndroidInjector<Activity> = activityInjector

override fun supportFragmentInjector(): AndroidInjector<Fragment> = supportFragmentInjector

private fun initDagger(){
    DaggerAppComponent
        .builder()
        .application(this)
        .build()
        .injectApp(this)
}

Затем класс AppComponent

@Singleton
@Component(
modules = [
    AppModule::class,
    UiModule::class,
    AndroidSupportInjectionModule::class,
    AndroidInjectionModule::class
])interface AppComponent : AndroidInjector<MyApp> {

   @Component.Builder
   interface Builder {
       @BindsInstance
       fun application(application: MyApp): Builder

       fun build(): AppComponent
   }

    fun injectApp(app: MyApp)
}

Здесь нас интересовал UiModule :: class

@Module
abstract class UiModule {

    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @PerFragment
    @ContributesAndroidInjector(modules = [(FilterModule::class)])
    abstract fun contributeFilterFragment(): FilterFragment
}

у вас уже есть ViewModelFactory, поэтому я не вставляю этот код. Затем FilterModule

@Module
abstract class FilterModule {

   @Binds
   @IntoMap
   @PerFragment
   @ViewModelKey(FilterViewModel::class)
   abstract fun bindViewModel(viewModel: FilterViewModel): ViewModel
}

и, наконец, FilterFragment и FilterViewModel

class FilterFragment : BottomSheetDialogFragment() {

   @Inject
   lateinit var factory: ViewModelProvider.Factory

   private lateinit var binding: FragmentFilterBinding
   private lateinit var viewModel: FilterViewModel

   override fun onAttach(context: Context?) {
       AndroidSupportInjection.inject(this)
       super.onAttach(context)
   }

   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       binding = getDataBinding(inflater, R.layout.fragment_filter, container)
       viewModel = getViewModel(factory)
       binding.viewModel = viewModel
       return binding.root
   }
}

class FilterViewModel @Inject constructor(private val testUseCase:TestUseCase) : BaseViewModel() {
     //do something
}

макет fragment_filter

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/tools">

<data>

    <variable
        name="viewModel"
        type="com.myapp.presentation.screen.filter.FilterViewModel" />
</data>
   .......

getDataBinding () и getViewModel () - функции расширения

fun <T : ViewDataBinding> Fragment.getDataBinding(inflater: LayoutInflater, @LayoutRes layoutId: Int, container: ViewGroup?): T =
    DataBindingUtil.inflate(inflater, layoutId, container, false)

inline fun <reified T : BaseViewModel> Fragment.getViewModel(factory: ViewModelProvider.Factory = ViewModelProviders.DefaultFactory(activity!!.application)): T =
    ViewModelProviders.of(this, factory).get(T::class.java)
person Alexandr Sushkov    schedule 29.11.2018