问题
I am new to dagger 2 and kotlin both. Getting lateinit property not initialized.
I have a module which have few @Provides methods but one of the class not able to create object which used @Inject and lateinit.
Login service takes "LoginAPI" as parameter and works fine but as i want all my login related API's to use the same service. There is one more API related "LoginWithOrgAPI".
Now my need is to get any API object when needed in the LoginService class. So i tries using lateinit with @Inject as show in LoginService class but its not working.
@Module(includes = [(NetworkingModule::class)])
class LoginModule {
@Provides
fun provideLoginApi(retrofit: Retrofit): LoginApi =
retrofit.create(LoginApi::class.java)
@Provides
fun provideLoginWithOrgApi(retrofit: Retrofit): LoginWithOrgApi =
retrofit.create(LoginWithOrgApi::class.java)
@Provides
fun provideLoginService(api: LoginApi): LoginService =
LoginService(api)
@Provides
fun provideLoginInteractor(apiService: LoginService): LoginInteractor =
LoginInteractor(apiService)
}
// adding LoginService class
class LoginService(val loginAPI: LoginApi) {
@Inject
lateinit var loginWithOrgApi: LoginWithOrgApi
fun loginAPIService(user: String, password: String?, extension: String, otp: String?,
hardwareId: String): Single<LoginAPIResponseData> {
password?.let {
return loginAPI.getLogin(user, it, extension, null, hardwareId)
}?: run {
return loginAPI.getLogin(user, null, extension, otp, hardwareId)
}
}
fun loginWithOrg(user: String, password: String?, extension: String, otp: String?,
userId: String, hardwareId: String): Single<LoginAPIResponseData>{
password?.let {
return loginWithOrgApi.getLogin(user, it, extension, null, userId, hardwareId)
}?: run {
return loginWithOrgApi.getLogin(user, null, extension, otp, userId, hardwareId)
}
}
}
// component
@Component(modules = [(LoginModule::class)])
interface LoginComponent {
fun loginInteractor(): LoginInteractor
}
// api interface
interface LoginWithOrgApi {
@POST("access/v1/login/")
@FormUrlEncoded
fun getLogin(@Field("user") user: String,
@Field("password") password: String?,
@Field("mobile_extension") extension: String,
@Field("otp") otp: String?,
@Field("user_id") userId: String,
@Field("hardware_id") hardwareId: String): Single<LoginAPIResponseData>
}
Getting the crash saying "lateinit" property not initialized when trying to call method "loginWithOrg"
My understanding is that once define and provided through module, i can get the object through @Inject in the dependency graph but something is missing here.
// my objective for LoginService class
class LoginService() {
@Inject
var loginWithOrgApi: LoginWithOrgApi
@Inject
var loginApi: LoginApi
fun loginAPIService(user: String, password: String?, extension: String, otp: String?,
hardwareId: String): Single<LoginAPIResponseData> {
password?.let {
return loginAPI.getLogin(user, it, extension, null, hardwareId)
}?: run {
return loginAPI.getLogin(user, null, extension, otp, hardwareId)
}
}
fun loginWithOrg(user: String, password: String?, extension: String, otp: String?,
userId: String, hardwareId: String): Single<LoginAPIResponseData>{
password?.let {
return loginWithOrgApi.getLogin(user, it, extension, null, userId, hardwareId)
}?: run {
return loginWithOrgApi.getLogin(user, null, extension, otp, userId, hardwareId)
}
}
}
回答1:
Because you are mixing two independent things: member injection via void inject(MyClass myClass);
and constructor injection.
In fact, you even have a separate field that "ought to be member-injected", even though you could technically receive that as a constructor param?
class LoginService(val loginAPI: LoginApi) { // <-- constructor param + field @Inject lateinit var loginWithOrgApi: LoginWithOrgApi // <-- why is this a lateinit member injected field? // this could also be constructor param
So it should be as follows.
@Module(includes = [(NetworkingModule::class)])
class LoginModule {
@Provides
fun loginApi(retrofit: Retrofit): LoginApi =
retrofit.create(LoginApi::class.java)
@Provides
fun loginWithOrgApi(retrofit: Retrofit): LoginWithOrgApi =
retrofit.create(LoginWithOrgApi::class.java)
//@Provides
//fun provideLoginService(api: LoginApi): LoginService =
// LoginService(api)
//@Provides
//fun provideLoginInteractor(apiService: LoginService): LoginInteractor =
// LoginInteractor(apiService)
}
and
class LoginService @Inject constructor(
val loginAPI: LoginApi,
val loginWithOrgApi: LoginWithOrgApi
) {
fun loginAPIService(user: String, password: String?, extension: String, otp: String?,
hardwareId: String): Single<LoginAPIResponseData> {
password?.let { password ->
return loginAPI.getLogin(user, password, extension, null, hardwareId)
}?: run {
return loginAPI.getLogin(user, null, extension, otp, hardwareId)
}
}
fun loginWithOrg(user: String, password: String?, extension: String, otp: String?,
userId: String, hardwareId: String): Single<LoginAPIResponseData>{
password?.let { password ->
return loginWithOrgApi.getLogin(user, password, extension, null, userId, hardwareId)
}?: run {
return loginWithOrgApi.getLogin(user, null, extension, otp, userId, hardwareId)
}
}
}
and
class LoginInteractor @Inject constructor(
val apiService: LoginService
) {
...
}
You own those classes, so there is no reason to use @field:Inject lateinit var
+ void inject(MyClass myClass);
here.
来源:https://stackoverflow.com/questions/54288418/kotlin-lateinit-not-working-with-inject-annotation