简体   繁体   中英

Inject retrofit android kotlin

ApiModule.kt

@Module
class ApiModule {

    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    @Singleton
    fun provideUserApi(retrofit: Retrofit): HeroesApi {
        return retrofit.create(HeroesApi::class.java)
    }


    @Provides
    @Singleton
    fun provideApiManager(): ApiManager {
        return ApiManager()
    }
}

ApiManager.kt

class ApiManager {

    @Inject
    lateinit var mRetrofit: Retrofit

    fun getAllHeroes(): MutableLiveData<Result<List<Hero>>> {
        val mHeroesApi = mRetrofit.create(HeroesApi::class.java)
        return NetworkHandler<List<Hero>>().makeCall(mHeroesApi.getAllHeroes())
    }
}

HeroesApi.kt

interface HeroesApi {

    @GET("/marvel")
    fun getAllHeroes(): Call<List<Hero>>

}

Error i am getting

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property mRetrofit has not been initialized
        at com.hardik.repository.network.ApiManager.getAllHeroes(ApiManager.kt:17)
        at com.hardik.repository.Repository.getHeroesFromNetwork(Repository.kt:16)
        at com.hardik.androidtemplate.usecase.GetHeroesUseCase.execute(GetHeroesUseCase.kt:14)
        at com.hardik.androidtemplate.viewmodel.HeroListViewModel.<init>(HeroListViewModel.kt:9)

Let me know for more details

You don't need to inject Retrofit instance in your ApiManager . You already have Provide method for HeroesApi in your ApiModule so you can directly pass it. First change your ApiManager with:

class ApiManager(private val mHeroesApi: HeroesApi) {

    fun getAllHeroes(): MutableLiveData<Result<List<Hero>>> {
        return NetworkHandler<List<Hero>>().makeCall(mHeroesApi.getAllHeroes())
    }
}

Then change your ApiModule

@Module
class ApiModule {

   // Rest code same as it is already

    @Provides
    @Singleton
    // Since you already have Provide method which provides HerosApi,
    // Dagger will automatically inject this below.
    fun provideApiManager(herosApi: HerosApi): ApiManager {
        return ApiManager(herosApi)
    }
}

OR

You can simply change your ApiManager to have HorseApi injected into constructor and you won't need to have Provide method for ApiManager even. For this, change ApiManager with following:

// Notice the @Inject before constructor
class ApiManager @Inject constructor(private val mHeroesApi: HeroesApi) {

    fun getAllHeroes(): MutableLiveData<Result<List<Hero>>> {
        return NetworkHandler<List<Hero>>().makeCall(mHeroesApi.getAllHeroes())
    }
}

and then, you can remove Provide method for ApiManager from ApiModule because your ApiManager only needs HerosApi in constructor and you have defined Provide method which returns HerosApi so dagger already knows how to construct your ApiManager .

So your ApiModule will finally look like this:

@Module
class ApiModule {

    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    @Singleton
    fun provideUserApi(retrofit: Retrofit): HeroesApi {
        return retrofit.create(HeroesApi::class.java)
    }
    // There's no need for providing ApiManager.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM