所以我对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()
}
}
此外,完整的错误代码已添加到顶部。
答案 0 :(得分:0)
在您使用命名注释的每种情况下,请尝试@Inject @field:Named
而不是@Inject @Named
。它帮助了我。
答案 1 :(得分:0)
好的,在这个单独的案例中,原因是在活动中对Fragment
个对象进行了非正确的分配,并将它们作为自己的属性进行操作 - 更具体地说,在MainActivity
内部,它们使用字段扩展了基类注射局部用药。
所以是的,匕首错误日志给了间接暗示在哪里挖掘。
答案 2 :(得分:0)
您似乎想念AndroidInjectionModule
(AndroidSupportInjectionModule
(如果使用支持片段,则为AppComponent
)。
应为:
@Component(modules = {AndroidInjectionModule.class, MainAppModule.class}