MVP Presenter未正确注入

时间:2017-07-28 21:17:59

标签: android dependency-injection kotlin dagger-2

我正在尝试将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()
    }
}

1 个答案:

答案 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修改(来自PresenterBasePresenterLoginPresenter),则会开始编译并正常工作。

我不确定为什么Dagger尝试注入错误类型或无法理解它是同一类型。注释处理时看起来像bug。所以最简单的解决方案 - 不要使用out修饰符 和Dagger一起。