'Hilt cannot be injected when using ViewModelProvider.Factory to obtain ViewModel

This is the fragment super class BaseFragment,I used a custom ViewModelStore to install the viewmodel in the activity,

abstract class BaseFragment<B:ViewDataBinding, VM:BaseViewModel, AVM:BaseSerialViewModel>:Fragment() {
    var mfBinding:B?=null
    var mfViewModel:VM?=null
    var mActivityVM:AVM?=null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        //In some cases, I want to clean up the Fragment's ViewModelStore
        if(xxx){
           getVmStore().clear()
        }

        mfViewModel = ViewModelProvider(getVmStore(), getViewModelFactory()).get(vmClazz)
    }

    open fun getVmStore(): ViewModelStore {
        return (requireActivity() as BaseActivity<out ViewDataBinding, out BaseSerialViewModel>).fragmentVmStore
    }

    open fun getViewModelFactory(): ViewModelProvider.Factory {
//        return SavedStateViewModelFactory(activity?.application, this)

//        return null
//        return HiltViewModelFactory.createInternal(requireActivity(), requireActivity(), null, object :ViewModelProvider.Factory{
//            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
//                return modelClass.newInstance()
//            }
//        })

        return object :ViewModelProvider.Factory{
            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
                return modelClass.newInstance()
            }
        }
    }
}

This class HomeActivity contains LoginFragment

class HomeActivity:BaseActivity{
      //I want to control fragment in unity
      val fragmentVmStore by lazy { ViewModelStore() }
}

LoginFragment:BaseFragment Inside has used @AndroidEntryPoint

LoginFragmentVM

@HiltViewModel
class LoginFragmentVM @Inject constructor():BaseViewModel() {

    @NetWorkModule.bindUserBaseUrl
    @Inject
    lateinit var retrofit: Retrofit
    private val netApi: ApiInterface by lazy { retrofit.create(ApiInterface::class.java) }
}

But the result of the final operation is: hilt does not initialize retrofit, and creates the content of retrofit. I have tested it and it is normal. I don't know what's wrong



Solution 1:[1]

First of all, you don't need to ViewModelFactory. you can now just use KTX viewModels() directly

private val viewModel: MyViewModel by viewModels()

then you should build module for retrofit then inject it in viewModel class, sth like this

@InstallIn(SingletonComponent::class)
@Module
class NetworkModule {



 @Singleton
    @Provides
    fun provideRetrofit(moshi: Moshi, @Named("cached") client: OkHttpClient): Retrofit.Builder {
        return Retrofit.Builder()
            .client(client)
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    }

    @Provides
    @Singleton
    fun provideWeatherService(retrofit: Retrofit.Builder): WeatherApi {
        return retrofit.baseUrl(Constants.NetworkService.BASE_URL_WEATHER)
            .build()
            .create(WeatherApi::class.java)
    }
}

then you can inject it to your classes depend on your architecture but it's better to use constructor injection like the code below

   class CurrentWeatherRemoteDataSource @Inject constructor(private val api: WeatherApi) {

    fun getCurrentWeatherByGeoCords(lat: Double, lon: Double, units: String): Single<CurrentWeatherResponse> = api.getCurrentByGeoCords(lat, lon, units)
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mojtaba Shirkhani