android.support.v4.app.FragmentManager 不能在没有 @Provides- 或 @Produces- 注释的方法的情况下提供。

3

我对Dagger还比较陌生,正尝试将Kotlin MVP项目与包含独立片段和独立导航的活动“daggerify”。

由于我使用了基于支持库的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
    }
}

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
}

我把Fragment视为独立的视图,因此每个Fragment目前都有一个视图模块和一个Presenter模块。以下是片段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上移一级,到主组件的模块数组中。
我希望这是框架相关的代码生成问题,而且我对支持机制的行为理解不足,因为所有模块部分都应该包含此注释。
从MyApp类代码片段可以看出,目前我被卡在了扩展MultiDexApplication上,所以我想知道这个问题是否与MultiDex支持有关。
这种情况对我来说看起来很奇怪,所以我希望更有经验的dagger用户能够指点我正确的方向。
编辑:
这里是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?这可能解释了你的问题。请包含完整的错误信息和相关代码,例如:https://dev59.com/C1cP5IYBdhLWcg3wDmch - David Medenjak
@DavidMedenjak,感谢您的回复!我编辑了问题。所以我尝试从所有相关代码中删除@Named(...),但目前没有任何变化:(无论如何,感谢链接-也许我会在其中找到有趣的东西。 - kkaun
@DavidMedenjak,实际上我已经尝试在代码中添加@Named,以及将其全部删除 :) 只是第一次阅读回复时错过了线索。 - kkaun
在添加了命名注释后,是否出现了相同的错误?我可以想象你在BaseFragment中有一个类似的错误。添加@Named应该解决你的问题。请仔细检查你的错误。 - David Medenjak
添加/删除所需字段上的@Named@field:Named后,堆栈跟踪没有改变。因此我想知道:@Provides提供程序模块的方法是否可能是原因?我应该尝试其他@Qualifier或其他东西吗?在这里我必须说,我也尝试完全从模块的提供程序中删除@Named,但什么也没有改变。另一个想法是:原因可能是抓取基类(在我的情况下为BaseActivitiy),注入字段并将它们用作扩展活动中的属性,例如fragmentManager?.putFragment()fragmentManager!!.putFragment() - kkaun
编辑了问题并添加了“BaseFragment”代码。 - kkaun
3个回答

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

0

好的,在这个特定的情况下,原因在于在活动中没有正确分配Fragment对象,并将它们作为自己的属性进行操作 - 更具体地说,在MainActivity内部,它扩展了具有主题类型的字段注入的基类。

所以是的,Dagger错误日志给出了间接提示要挖掘的地方。


0

看起来你缺少已经在AppComponent中安装 AndroidInjectionModule (如果你使用支持片段,则为AndroidSupportInjectionModule)。

应该像这样:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接