【问题标题】:android.support.v4.app.FragmentManager cannot be provided without an @Provides- or @Produces-annotated method如果没有 @Provides- 或 @Produces-annotated 方法,则无法提供 android.support.v4.app.FragmentManager
【发布时间】:2017-12-18 21:55:58
【问题描述】:

所以我对 Dagger 很陌生,并试图用活动、独立片段和独立导航来“daggerify”Kotlin MVP 项目。

事实上,我使用了基于支持库的 Fragment 的大量视图,这让我尝试了最近的 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
    }
}

应用组件:

@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 个视图模块和 1 个演示器模块 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 匕首依赖项:

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 类代码 sn-p 可以看出,目前我坚持扩展 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()
    }
}

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

【问题讨论】:

  • 我会你尝试@Inject fm : FragmentManager而不是@Inject @Named(ACTIVITY_FRAGMENT_MANAGER) fm : FragmentManager?这可以解释你的问题。请附上完整的错误信息和相关代码,例如看这里:stackoverflow.com/q/44912080/1837367
  • @DavidMedenjak,感谢您的回复!我编辑了这个问题。所以我试图从所有相关代码中删除 @Named(...) ,但现在没有任何变化:( 无论如何,感谢链接 - mb 我会发现它很有趣。
  • @DavidMedenjak,实际上我已经尝试将@Named 放在代码中并将其全部删除:) 第一次阅读回复时错过了线索。
  • 添加命名注释后是否出现相同错误?我可以想象你的 BaseFragment 中有类似的错误。添加@Named 应该可以解决您的问题。请彻底检查您的错误
  • 嗯,在所需字段上添加/删除 @Named@field:Named 后,堆栈跟踪没有改变。因此我想知道:@Provides 提供程序模块的方法可能是原因吗?我应该尝试其他@Qualifier 还是smth?在这里我不得不说我也试图从模块的提供者中完全删除@Named,但没有任何改变。另一个想法是:原因可能在于获取基类(在我的情况下为BaseActivitiy),注入字段并将它们用作扩展活动的属性,例如fragmentManager?.putFragment()fragmentManager!!.putFragment()

标签: android kotlin dagger-2 dagger


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    好的,在这个单独的情况下,原因是在活动中不正确地分配 Fragment 对象并将它们作为自己的属性进行操作 - 更具体地说,在 MainActivity 内部,它通过提交的主题类型注入扩展了基类.

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

    【讨论】:

      【解决方案3】:

      您好像不见了AndroidInjectionModule (或AndroidSupportInjectionModule,如果你使用支持片段)安装在你AppComponent上。

      应该是这样的:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-02
        • 1970-01-01
        • 1970-01-01
        • 2020-05-20
        • 2019-02-26
        • 1970-01-01
        相关资源
        最近更新 更多