【发布时间】: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