【问题标题】:Inject retrofit android kotlin注入改造android kotlin
【发布时间】:2020-01-01 09:18:03
【问题描述】:

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

}

我遇到的错误

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)

让我知道更多详情

【问题讨论】:

    标签: android kotlin retrofit dagger-2


    【解决方案1】:

    您不需要在您的ApiManager 中注入Retrofit 实例。您的ApiModule 中已经有HeroesApiProvide 方法,因此您可以直接传递它。首先将您的 ApiManager 更改为:

    class ApiManager(private val mHeroesApi: HeroesApi) {
    
        fun getAllHeroes(): MutableLiveData<Result<List<Hero>>> {
            return NetworkHandler<List<Hero>>().makeCall(mHeroesApi.getAllHeroes())
        }
    }
    

    然后更改您的 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)
        }
    }
    

    您可以简单地将ApiManager 更改为将HorseApi 注入构造函数,您甚至不需要为ApiManager 使用Provide 方法。为此,将 ApiManager 更改为:

    // 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())
        }
    }
    

    然后,您可以从ApiModule 中删除ApiManagerProvide 方法,因为您的ApiManager 在构造函数中只需要HerosApi,并且您已经定义了返回HerosApiProvide 方法,所以匕首已经知道如何构造你的ApiManager

    所以您的 ApiModule 最终将如下所示:

    @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.
    }
    

    【讨论】:

    • 同意你的回答(+1)。但是我想将改造作为现场注入(不是通过构造函数)那么我该怎么办?
    • 字段注入仅适用于您无法自己构建的类,例如 Activity。对于您可以自己构建的 ApiManager 等其他类,您应该始终只使用构造函数注入。如果你还想进行字段注入,那么你需要用fun inject(apiManager: ApiManager)之类的方法为ApiManager创建一个组件,然后在ApiManager的init bloc中,你需要写yourApiManagerComponent.inject(this)。我不认为你愿意为现场注入做这一切,这里不推荐:)
    猜你喜欢
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2022-01-04
    • 2018-03-08
    相关资源
    最近更新 更多