我正在尝试将Mindorks advanced MVP sample中的一些转换为Kotlin,但我正在学习Kotlin和Dagger 2,但我遇到了Dagger2编译问题。我在这里上课,但非常接近!不介意不整洁,我打算在编译后梳理每个班级。如果遗漏了什么,请告诉我。错误归结为我的演示者类未正确注入活动。错误如下:
e: D:\_Dev\repo\app\build\tmp\kapt3\stubs\debug\com\xxx\di\component\ActivityComponent.java:8: error: com.xxx.login.LoginMVP.Presenter<com.xxx.login.LoginMVP.View,? extends com.xxx.login.LoginMVP.Interactor> cannot be provided without an @Provides- or @Produces-annotated method.
e:
e: public abstract void inject(@org.jetbrains.annotations.NotNull()
e: ^
e: com.xxx.login.LoginMVP.Presenter<com.xxx.login.LoginMVP.View,? extends com.xxx.login.LoginMVP.Interactor> is injected at
e: com.xxx.login.LoginActivity.presenter
e: com.xxx.login.LoginActivity is injected at
e: com.xxx.di.component.ActivityComponent.inject(activity)
e: java.lang.IllegalStateException: failed to analyze: org.jetbrains.kotlin.kapt3.diagnostic.KaptError: Error while annotation processing
修改
Here is a repo with the failing code,使用Android Studio的最新canary版本构建
BaseActivity.kt
abstract class BaseActivity : AppCompatActivity(), MvpView {
val activityComponent: ActivityComponent by lazy {
DaggerActivityComponent.builder()
.applicationComponent((application as App).applicationComponent)
.activityModule(ActivityModule(this))
.build()
}
}
BasePresenter.kt
open class BasePresenter<V : MvpView, out I: MvpInteractor>
@Inject constructor(private val mvpInteractor: I) : MvpPresenter<V, I> {
private var mvpView: V? = null
override fun onAttach(mvpView: V) {
this.mvpView = mvpView
}
override fun onDetach() {
mvpView = null
}
override fun getMvpView(): V? {
return mvpView
}
override fun getInteractor(): I {
return mvpInteractor
}
}
MvpPresenter.kt(MvpView和MvpInteractor是基本的空接口)
interface MvpPresenter<V: MvpView, out I: MvpInteractor> {
fun onAttach(mvpView: V)
fun onDetach()
fun getMvpView(): V?
fun getInteractor(): I
}
App.kt
class App: Application() {
lateinit var applicationComponent: ApplicationComponent
override fun onCreate() {
super.onCreate()
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(ApplicationModule(this)).build()
applicationComponent.inject(this)
}
fun getComponent(): ApplicationComponent {
return applicationComponent
}
fun setComponent(applicationComponent: ApplicationComponent) {
this.applicationComponent = applicationComponent
}
}
ApplicationComponent.kt
@Singleton
@Component(modules = arrayOf(ApplicationModule::class))
interface ApplicationComponent {
fun inject(app: App)
@ApplicationContext fun context(): Context
fun application(): Application
//Pref helper
//Api helper
}
ApplicationModule.kt
@Module
class ApplicationModule(val application: Application) {
@Provides
@ApplicationContext
fun provideContext(): Context = application
@Provides
fun provideApplication(): Application = application
//Provide api helper
//Provide pref helper
//Provide api key etc.
}
ActivityModule.kt
@Module
class ActivityModule(val activity: AppCompatActivity) {
@Provides
fun provideContext(): Context = activity
@Provides
fun provideActivity(): AppCompatActivity = activity
@Provides
fun provideLoginPresenter(presenter: LoginPresenter<LoginMVP.View, LoginMVP.Interactor>):
LoginMVP.Presenter<LoginMVP.View, LoginMVP.Interactor> {
return presenter
}
@Provides
fun provideLoginMvpInteractor(interactor: LoginInteractor):
LoginMVP.Interactor {
return interactor
}
}
ActivityComponent.kt
@PerActivity
@Component(dependencies = arrayOf(ApplicationComponent::class), modules = arrayOf(ActivityModule::class))
interface ActivityComponent {
fun inject(activity: LoginActivity)
}
LoginActivity.kt
class LoginActivity : BaseActivity(), LoaderCallbacks<Cursor>, LoginMVP.View {
@Inject lateinit var presenter: LoginMVP.Presenter<LoginMVP.View, LoginMVP.Interactor>
private var authTask: UserLoginTask? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
activityComponent.inject(this)
email_sign_in_button.setOnClickListener { presenter.onServerLoginClick(email.text.toString(), password.text.toString()) }
presenter.onAttach(this)
}
}
LoginMVP.kt
interface LoginMVP {
interface Interactor : MvpInteractor {
}
@PerActivity
interface Presenter<V : LoginMVP.View, out I : LoginMVP.Interactor>
: MvpPresenter<V, I> {
fun onServerLoginClick(email: String, password: String)
}
interface View : MvpView {
fun openMainActivity()
}
}
答案 0 :(得分:3)
这不是一个完整的答案,但非常接近。
问题出在out
修饰符中。使用此修改器Dagger尝试注入
com.xxx.login.LoginMVP.Presenter<com.xxx.login.LoginMVP.View,? extends com.xxx.login.LoginMVP.Interactor>
但你只提供
com.xxx.login.LoginMVP.Presenter<com.xxx.login.LoginMVP.View, com.xxx.login.LoginMVP.Interactor>
(在函数provideLoginPresenter
中)。
因此,如果删除所有out
修改(来自Presenter
,BasePresenter
,LoginPresenter
),则会开始编译并正常工作。
我不确定为什么Dagger尝试注入错误类型或无法理解它是同一类型。注释处理时看起来像bug。所以最简单的解决方案 - 不要使用out
修饰符
和Dagger一起。