HILT: репозиторий свойств lateinit не инициализирован в ViewModel - PullRequest
0 голосов
/ 10 июля 2020

Я столкнулся с этой проблемой в многомодульном проекте android с HILT.

 kotlin.UninitializedPropertyAccessException: lateinit property repository has not been initialized in MyViewModel

Мои модули:

  1. Модуль приложения
  2. Модуль Viewmodel
  3. UseCase Module
  4. DataSource Module

'App Module'

@AndroidEntryPoint
class MainFragment : Fragment() {
private lateinit var viewModel: MainViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View {
    return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
    viewModel.test()
}}

'ViewModel Module'

class MainViewModel @ViewModelInject constructor(private val repository: MyUsecase): ViewModel() {
fun test(){
    repository.test()
}}

'UseCase Module'

class MyUsecase @Inject constructor() {

@Inject
lateinit var feature: Feature

fun doThing() {
    feature.doThing()
}

@Module
@InstallIn(ApplicationComponent::class)
object FeatureModule {
    @Provides
    fun feature(realFeature: RealFeature): Feature = realFeature
}
}

'DataSource Module'

interface Feature {
fun doThing()
}

class RealFeature : Feature {
override fun doThing() {
    Log.v("Feature", "Doing the thing!")
}
}

Зависимости:

MyFragment ---> MyViewModel ---> MyUseCase ---> DataSource

что я сделал не так с этим кодом, пожалуйста, исправьте его.

Ответы [ 3 ]

0 голосов
/ 11 июля 2020

Помимо перемещения всего вашего материала в конструктор, ваш RealFeature не внедряется, потому что вы создаете его вручную, а не позволяете Dagger построить его за вас. Обратите внимание, как ваш FeatureModule напрямую вызывает конструктор для RealFeature и возвращает его для метода @Provides. Dagger будет использовать этот объект как есть, поскольку думает, что вы выполнили для него все настройки. Внедрение поля работает, только если вы позволите Dagger построить его.

Ваш FeatureModule должен выглядеть так:

@Module
@InstallIn(ApplicationComponent::class)
object FeatureModule {
    @Provides
    fun feature(realFeature: RealFeature): Feature = realFeature
}

Или с аннотацией @Binds:

@Module
@InstallIn(ApplicationComponent::class)
interface FeatureModule {
    @Binds
    fun feature(realFeature: RealFeature): Feature
}

Это также подчеркивает, почему вам следует перейти к внедрению конструктора; с внедрением конструктора эта ошибка была бы невозможна.

0 голосов
/ 29 июля 2020

Во-первых, я думаю, что вам не хватает @Inject в вашем классе RealFeature, поэтому Hilt знает, как внедрить зависимость. Во-вторых, если вы хотите внедрить в класс, который не является частью точек входа, поддерживаемых Hilt, вам необходимо определить собственную точку входа для этого класса.

В дополнение к модулю, который вы написали с помощью @Provides метод, вам нужно указать Hilt, как можно получить доступ к зависимости.

В вашем случае вы должны попробовать что-то вроде этого:

@EntryPoint
@InstallIn(ApplicationComponent::class)
interface FeatureInterface {
    fun getFeatureClass(): Feature
}

Затем, когда вы захотите его использовать, напишите примерно так:

        val featureInterface =
        EntryPoints.get(appContext, FeatureInterface::class.java)
        val realFeature = featureInterface.getFeatureClass()

Вы можете найти дополнительную информацию здесь:

https://dagger.dev/hilt/entry-points

https://developer.android.com/training/dependency-injection/hilt-android#not -поддерживается

0 голосов
/ 10 июля 2020

Проблема в коде в том, что @ViewModelInject не работает как @Inject в других классах. Вы не можете выполнить внедрение поля в ViewModel.

Вам следует сделать:

class MainViewModel @ViewModelInject constructor(
  private val myUseCase: MyUsecase
): ViewModel() {

  fun test(){
    myUseCase.test()
  }
}

Рассмотрите возможность использования того же шаблона для класса MyUsecase. Зависимости должны передаваться в конструкторе, а не @Inject в теле класса. Такой вид побеждает цель внедрения зависимостей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...