I am learning Kotlin and Dagger 2 at the same time, trying to convert some of the Mindorks advanced MVP sample to Kotlin, but I have problems compiling Dagger2. I am swimming in the classes here, but very close! Ignore the sloppiness, I'm going to comb every class after compiling it. If something is missing, please let me know. The error boils down to the fact that my presenter class was not properly enforced. The error is read as follows:
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
EDIT:
Here is a repo with unsuccessful code built using the latest canary build of 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 and MvpInteractor - basic empty interfaces)
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
}
ApplicationModule.kt
@Module
class ApplicationModule(val application: Application) {
@Provides
@ApplicationContext
fun provideContext(): Context = application
@Provides
fun provideApplication(): Application = application
}
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()
}
}