如果没有@ Provide-或@ Produces-annotated方法

时间:2017-12-18 21:55:58

标签: android kotlin dagger-2 dagger

所以我对Dagger很陌生,试图通过活动加独立片段和独立导航来“摧毁”Kotlin MVP项目。

我使用基于支持lib的片段的好几个视图的事实让我尝试了最近的dagger android支持功能。 在对组件图构建进行了一些努力之后,我遇到了由此错误表示的问题:

e: ...\MyApp\app\build\tmp\kapt3\stubs\debug\com\...\di\app\MyAppComponent.java:6: error: [dagger.android.AndroidInjector.inject(T)] android.support.v4.app.FragmentManager cannot be provided without an @Provides- or @Produces-annotated method.
e: 
e: public abstract interface MyAppComponent extends dagger.android.AndroidInjector<myapp.ui.MyApp> {
e:                 ^
e:       android.support.v4.app.FragmentManager is injected at
e:           myapp.ui.common.BaseActivity.fragmentManager
e:       myapp.ui.main.MainActivity is injected at
e:           dagger.android.AndroidInjector.inject(arg0)
e: java.lang.IllegalStateException: failed to analyze: org.jetbrains.kotlin.kapt3.diagnostic.KaptError: Error while annotation processing
    at org.jetbrains.kotlin.analyzer.AnalysisResult.throwIfError(AnalysisResult.kt:57)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:137)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:158)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:61)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:107)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:51)
    at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:92)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:386)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:96)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:892)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:96)
    at org.jetbrains.kotlin.daemon.common.DummyProfiler.withMeasure(PerfUtils.kt:137)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.checkedCompile(CompileServiceImpl.kt:919)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.doCompile(CompileServiceImpl.kt:891)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:385)
    at sun.reflect.GeneratedMethodAccessor95.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:346)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.jetbrains.kotlin.kapt3.diagnostic.KaptError: Error while annotation processing
    at org.jetbrains.kotlin.kapt3.AnnotationProcessingKt.doAnnotationProcessing(annotationProcessing.kt:90)
    at org.jetbrains.kotlin.kapt3.AnnotationProcessingKt.doAnnotationProcessing$default(annotationProcessing.kt:42)
    at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.runAnnotationProcessing(Kapt3Extension.kt:205)
    at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.analysisCompleted(Kapt3Extension.kt:166)
    at org.jetbrains.kotlin.kapt3.ClasspathBasedKapt3Extension.analysisCompleted(Kapt3Extension.kt:82)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM$analyzeFilesWithJavaIntegration$2.invoke(TopDownAnalyzerFacadeForJVM.kt:96)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:106)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:83)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:376)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:67)
    at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:96)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:367)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:132)
    ... 29 more

FAILED
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:kaptDebugKotlin'.

这是一些代码。

应用

class MyApp : MultiDexApplication(), HasActivityInjector {

    @Inject
    @JvmField
    var activityInjector: DispatchingAndroidInjector<Activity>? = null

    override fun onCreate() {
        super.onCreate()
        DaggerMyAppComponent.builder().create(this).inject(this)
    }

    override fun activityInjector(): AndroidInjector<Activity>? {
        return activityInjector
    }
}

AppComponent:

@Singleton
@Component(modules = [
    MyAppModule::class,
    DataModule::class,
    PreferencesModule::class,
    ServiceModule::class
])
interface MyAppComponent : AndroidInjector<MyApp> {

    @Component.Builder
    abstract class Builder : AndroidInjector.Builder<MyApp>()
}

的AppModule:

@Module(includes = [AndroidSupportInjectionModule::class])
abstract class MyAppModule {

    @Binds
    @Singleton
    abstract fun application(myApp: MyApp): Application

    @PerActivity
    @ContributesAndroidInjector(modules = [(MainActivityModule::class)])
    abstract fun mainActivityInjector(): MainActivity

    //... other activity injectors
}

BaseActivityModule:

@Module
abstract class BaseActivityModule {

    @Binds
    @PerActivity
    internal abstract fun activity(appCompatActivity: AppCompatActivity): Activity

    @Binds
    @PerActivity
    internal abstract fun activityContext(activity: Activity): Context

    @Module
    companion object {

        const val ACTIVITY_FRAGMENT_MANAGER = "BaseActivityModule.activityFragmentManager"

        @JvmStatic
        @Provides
        @Named(ACTIVITY_FRAGMENT_MANAGER)
        @PerActivity
        fun activityFragmentManager(activity: AppCompatActivity): FragmentManager {
            return activity.supportFragmentManager
        }
    }
}

BaseFragmentModule:

@Module
class BaseFragmentModule {

    @Module
    companion object {

        const val FRAGMENT = "BaseFragmentModule.fragment"
        const val CHILD_FRAGMENT_MANAGER = "BaseFragmentModule.childFragmentManager"

        @JvmStatic
        @Provides
        @Named(CHILD_FRAGMENT_MANAGER)
        @PerFragment
        fun childFragmentManager(@Named(FRAGMENT) fragment: Fragment): FragmentManager {
            return fragment.childFragmentManager
        }
    }
}

BaseChildFragmentModule:

@Module
class BaseChildFragmentModule {
    companion object {
        const val CHILD_FRAGMENT = "BaseChildFragmentModule.childFragment"
    }
}

示例MainActivityModule:

@Module(includes = [
    BaseActivityModule::class
])
abstract class MainActivityModule {

    @Binds
    @PerActivity
    abstract fun appCompatActivity(mainActivity: MainActivity): AppCompatActivity

    @PerFragment
    @ContributesAndroidInjector(modules = [LocationFragmentModule::class])
    abstract fun locationFragmentInjector(): LocationFragment

    //... other related fragments injection methods
}

我将片段视为独立视图,因此每个片段都有1个View Module和1个Presenter Module ATM。以下是片段的DI部分的样本:

@Module(includes = [BaseFragmentModule::class, LocationPresenterModule::class])
abstract class LocationFragmentModule {

    @Binds
    @Named(BaseFragmentModule.FRAGMENT)
    @PerFragment
    abstract fun fragment(locationFragment: LocationFragment): Fragment

    @Binds
    @PerFragment
    abstract fun locationView(locationFragment: LocationFragment): LocationView
}

@Module
abstract class LocationPresenterModule {

    @Binds
    @PerFragment
    abstract fun locationPresenter(locationPresenterImpl: LocationPresenterImpl): LocationPresenter
}

Gradle dagger依赖项:

implementation "com.google.dagger:dagger:$dagger_version"
kapt  "com.google.dagger:dagger-compiler:$dagger_version"
implementation "com.google.dagger:dagger-android:$dagger_version"
kapt  "com.google.dagger:dagger-android-processor:$dagger_version"
implementation "com.google.dagger:dagger-android-support:$dagger_version"
kapt  "com.google.dagger:dagger-android-support:$dagger_version"

我试图将AndroidSupportInjectionModule :: class提高一级到主组件的模块数组。

我希望这是与框架相关的代码生成问题,我对支持机制行为的理解很差, 因为@Provides所有模块的部分应该已经包含这个注释。

从MyApp类代码片段可以看出,目前我不得不扩展MultiDexApplication,所以我想这个问题可能与MultiDex支持有关。

这种情况对我来说很奇怪,所以我希望更有经验的匕首用户指出正确的方向。

修改

以下是 BaseActivity 代码:

abstract class BaseActivity : AppCompatActivity(), HasSupportFragmentInjector {

    @Inject
    @JvmField
    var navigationManager: NavigationManager? = null

    @Inject
    @JvmField
    var locationManager: MyLocationManagerImpl? = null

    @Inject
    @JvmField
    @Named(BaseActivityModule.ACTIVITY_FRAGMENT_MANAGER)
    //Tried to replace with option below
    //@field:Named(BaseActivityModule.ACTIVITY_FRAGMENT_MANAGER)
    var fragmentManager: FragmentManager? = null

    @Inject
    @JvmField
    var fragmentInjector: DispatchingAndroidInjector<Fragment>? = null

    override fun onCreate(@Nullable savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
    }

    override fun supportFragmentInjector(): AndroidInjector<Fragment>? {
        return fragmentInjector
    }
}

BaseFragment

abstract class BaseFragment : Fragment(), HasSupportFragmentInjector {

    @Inject
    @JvmField
    var activityContext: Context? = null

    @Inject
    @JvmField
    var parentActivity: FragmentActivity? = null

    @Inject
    @JvmField
    var fragmentListener: FragmentListener? = null

    @Inject
    @JvmField
    @Named(BaseFragmentModule.CHILD_FRAGMENT_MANAGER) 
    //Also tried option below
    //@field:Named(BaseFragmentModule.CHILD_FRAGMENT_MANAGER)
    var ownChildFragmentManager: FragmentManager? = null

    @Inject
    @JvmField
    var childFragmentInjector: DispatchingAndroidInjector<Fragment>? = null

    override fun onAttach(context: Context) {
        AndroidSupportInjection.inject(this)
        if (context is FragmentListener) {
            parentActivity = context as FragmentActivity
            fragmentListener = context
        }
        super.onAttach(context)
    }

    @Suppress("DEPRECATION")
    override fun onAttach(activity: Activity) {
        AndroidSupportInjection.inject(this)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            if(activity is FragmentListener) {
                parentActivity = activity as FragmentActivity
                fragmentListener = activity
            }
        }
        super.onAttach(activity)
    }

    override fun supportFragmentInjector(): AndroidInjector<Fragment>? {
        return childFragmentInjector
    }

    fun addChildFragment(@IdRes containerViewId: Int, fragment: Fragment) {
        childFragmentManager!!.beginTransaction()
                .add(containerViewId, fragment)
                .commit()
    }
}

此外,完整的错误代码已添加到顶部。

3 个答案:

答案 0 :(得分:0)

在您使用命名注释的每种情况下,请尝试@Inject @field:Named而不是@Inject @Named。它帮助了我。

答案 1 :(得分:0)

好的,在这个单独的案例中,原因是在活动中对Fragment个对象进行了非正确的分配,并将它们作为自己的属性进行操作 - 更具体地说,在MainActivity内部,它们使用字段扩展了基类注射局部用药。

所以是的,匕首错误日志给了间接暗示在哪里挖掘。

答案 2 :(得分:0)

您似乎想念AndroidInjectionModuleAndroidSupportInjectionModule(如果使用支持片段,则为AppComponent)。

应为:

@Component(modules = {AndroidInjectionModule.class, MainAppModule.class}