Как создать ViewModel в модуле динамических функций с помощью Dagger Hilt?

Попытка создать ViewModel в модуле динамических функций с private val viewModel: PostDetailViewModel by viewModels()

во фрагменте

class PostDetailFragment : DynamicNavigationFragment<FragmentPostDetailBinding>() {

    private val viewModel: PostDetailViewModel by viewModels()
    
    override fun getLayoutRes(): Int = R.layout.fragment_post_detail

    override fun bindViews() {
        // Get Post from navigation component arguments
        val post = arguments?.get("post") as Post
        dataBinding.item = post
        viewModel.updatePostStatus(post)
        
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        initCoreDependentInjection()
        super.onCreate(savedInstanceState)
    }

    private fun initCoreDependentInjection() {

        val coreModuleDependencies = EntryPointAccessors.fromApplication(
            requireActivity().applicationContext,
            DomainModuleDependencies::class.java
        )

        DaggerPostDetailComponent.factory().create(
            coreModuleDependencies,
            requireActivity().application
        )
            .inject(this)

    }
}

ошибка результатов

Caused by: java.lang.InstantiationException: java.lang.Class<com.x.post_detail.PostDetailViewModel> has no zero argument constructor

он работает в любом фрагменте модуля приложения, но не работает в модулях динамических функций. Как правильно добавлять ViewModels в модули динамических функций? Должен ли я создавать модели ViewModels в модуле приложения с помощью ViewModelFactory и получать их из модуля приложения?


person Thracian    schedule 31.08.2020    source источник
comment
Это помогает? code.luasoftware.com/tutorials/android /   -  person Skizo-ozᴉʞS    schedule 31.08.2020
comment
@ Skizo-ozᴉʞS, я изучаю это. Что заставляет его работать с ViewModel во фрагменте с by viewModels в функциональном модуле. Я вижу, что ViewModel создается внутри Activity, в модуле динамических функций или модуле приложения? Потому что мне не удалось создать ViewModel во фрагменте в модуле динамических функций.   -  person Thracian    schedule 31.08.2020


Ответы (1)


На основе этих официальных сообщений github

Документация по Hilt и DFM теперь доступна на сайте https://developer.android.com/training/dependency-injection/hilt-multi-module#dfm

Однако в целом, поскольку мы построены из подкомпонентов и монолитных компонентов, вы не сможете использовать стандартные механизмы Hilt, такие как @AndroidEntryPoint, с DFM.

К сожалению нет. @ViewModelInject использует Hilt ActivityRetainedComponent, который является монолитным, поэтому любой класс @ViewModelInject в вашем DFM не будет распознан.

кажется, что внедрение в ViewModel только с @ViewModelInject и by viewModels() в модуле динамических функций на данный момент невозможно.

На основе приложения-пледа я перестроил свой модуль Dagger в модуль динамических функций как

@InstallIn(FragmentComponent::class)
@Module
class PostDetailModule {

    @Provides
    fun providePostDetailViewModel(fragment: Fragment, factory: PostDetailViewModelFactory) =
        ViewModelProvider(fragment, factory).get(PostDetailViewModel::class.java)

    @Provides
    fun provideCoroutineScope() = CoroutineScope(Dispatchers.Main.immediate + SupervisorJob())

}

И ViewModel и ViewModelFactory являются

class PostDetailViewModel @ViewModelInject constructor(
    private val coroutineScope: CoroutineScope,
    private val getPostsUseCase: UseCase
) : ViewModel() {
 
    // Do other things
}

class PostDetailViewModelFactory @Inject constructor(
    private val coroutineScope: CoroutineScope,
    private val getPostsUseCase: UseCase
) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass != PostDetailViewModel::class.java) {
            throw IllegalArgumentException("Unknown ViewModel class")
        }
        return PostDetailViewModel(
            coroutineScope,
            getPostsUseCase
        ) as T
    }
}

И вводится во фрагмент в модуле динамических функций

class PostDetailFragment : Fragment() {

    @Inject
    lateinit var viewModel: PostDetailViewModel


    override fun onCreate(savedInstanceState: Bundle?) {
        initCoreDependentInjection()
        super.onCreate(savedInstanceState)
    }

    private fun initCoreDependentInjection() {

        val coreModuleDependencies = EntryPointAccessors.fromApplication(
            requireActivity().applicationContext,
            DomainModuleDependencies::class.java
        )

        DaggerPostDetailComponent.factory().create(
            dependentModule = coreModuleDependencies,
            fragment = this
        )
            .inject(this)
    }
}
person Thracian    schedule 31.08.2020