How to use Hilt with MVVM in fragments?

Viewed 74

In my fragments I would like to remove such lines:

val retrofitService = RetrofitService.getInstance(requireContext())
val mainRepository = MainRepository(retrofitService)
viewModel = ViewModelProvider(
this@FrgName,
AppVMFactory(mainRepository)
)[AppViewModel::class.java]

I have such view model:

class AppViewModel @Inject constructor(private val mainRepository: MainRepository) : ViewModel() {...}

such factory:

class AppVMFactory @Inject constructor(private val repository: MainRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return if (modelClass.isAssignableFrom(AppViewModel::class.java)) {
            AppViewModel(this.repository) as T
        } else {
            throw IllegalArgumentException("ViewModel Not Found")
        }
    }
}

such repository:

class MainRepository @Inject constructor(val retrofitService: RetrofitService) {
    suspend fun logIn(loginObject: JsonObject) = retrofitService.auth(loginObject)
....

}

and service contains all requests. As we know we can use in fragments viewmodels() call and for this purpose I have to add to build.gradle dependency. But due to the fact that I use ViewModelProvider.Factory it is impossible to use. I tried to inject viewmodel directly in VM class via @HiltViewModel annotation but I got such error:

Injection of an @HiltViewModel class is prohibited since it does not create a ViewModel instance correctly.
  Access the ViewModel via the Android APIs (e.g. ViewModelProvider) instead.
  Injected ViewModel: pkg.viewModel.AppViewModel

What I can see it that maybe I have to use another injection type which will provide VM for all fragments/dialogfragments and so on but I don't know about it. I have also some test activity on which I can use only:

@Inject
lateinit var viewModel: AppViewModel

and that is all. But I use a lot of fragments in the app so maybe it will be possible to add support for such functionality for fragments too?

Update

my retrofit service:

interface RetrofitService : UserModule {
    @POST("login")
    suspend fun auth(@Body body: JsonObject): Response<AppAuthModel> // main auth to the app

.....
    companion object {
        var retrofitService: RetrofitService? = null
        fun getInstance(context: Context): RetrofitService {
            val client = OkHttpClient.Builder()
                .addInterceptor(AppInterceptor(context))
                .connectTimeout(100, TimeUnit.SECONDS)
                .dispatcher(Dispatcher().apply {
                    maxRequests = 1
                })
                .readTimeout(100, TimeUnit.SECONDS).build()


            client.dispatcher.cancelAll()

            val retrofit = Retrofit.Builder()
                .baseUrl(BuildConfig.API_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

            retrofitService = retrofit.create(APIService::class.java)

            return retrofitService!!
        }

    }
}

my application class:

@HiltAndroidApp
class BaseApplication:Application()

provider for repository:

@Singleton
@Provides
fun provideApiService(retrofit: Retrofit): RetrofitService =
    retrofit.create(RetrofitService::class.java)

@Singleton
@Provides
fun providesRepository(apiService: RetrofitService) = MainRepository(apiService)
0 Answers
Related