'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 |