【问题标题】:MVP Presenter not injected correctlyMVP Presenter 未正确注入
【发布时间】:2017-07-28 21:17:59
【问题描述】:

我正在通过尝试将一些 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,使用最新的 Canary 版本的 Android Studio 构建

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

登录MVP.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()
    }
}

【问题讨论】:

  • 您介意将您当前的状态推送到 Github 吗?想看看。
  • 感谢@Ascorbin,我现在添加了一个回购链接。它是用最新的 Canary Android Studio 构建的,所以希望这不是问题。

标签: android dependency-injection kotlin dagger-2


【解决方案1】:

这不是一个完整的答案,但非常接近。

问题在于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 会尝试注入错误的类型或无法理解它是同一类型。注释处理时看起来像错误。所以最简单的解决方案 - 不要使用out 修饰符 用匕首。

【讨论】:

  • 干得好,谢谢。我只是按照 AS 告诉我的去做,这让我伤心了大约 6 个小时 :)
猜你喜欢
  • 2018-12-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-15
  • 1970-01-01
  • 2010-12-10
  • 2018-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多