我对SearchPresenter对象的注入有问题。我已经将依赖图修改了50多次,无法弄清问题是什么:
e: /home/alexandre/dev/projetos/gitlab/Cervejas/app/build/tmp/kapt3/stubs/debug/br/com/alexpfx/cervejas/di/AppComponent.java:8: error: [br.com.alexpfx.cervejas.di.beers.BeersComponent.inject(br.com.alexpfx.cervejas.beers.BeersFragment)] br.com.alexpfx.cervejas.search.SearchPresenter cannot be provided without an @Provides- or @Produces-annotated method.
public abstract interface AppComponent {
^
br.com.alexpfx.cervejas.search.SearchPresenter is injected at
br.com.alexpfx.cervejas.beers.BeersFragment.searchPresenter
br.com.alexpfx.cervejas.beers.BeersFragment is injected at
br.com.alexpfx.cervejas.di.beers.BeersComponent.inject(beersFragment)
我是这些组件和模块:
@Singleton
@Component(
modules = [AppModule::class, ServiceModule::class]
)
interface AppComponent {
fun inject (app: BeerApp)
fun plus (): LoginSubComponent
fun plus (searchModule: UntappedSearchModule): BeersComponent
}
@Module
class AppModule(val app: BeerApp) {
@Singleton
@Provides
fun app(): BeerApp = app
}
@Module
class ServiceModule {
companion object {
private const val BASE_URL = "https://api.untappd.com/"
}
@Singleton
@Provides
fun provideUntappedConfig(): UntappdConfig {
return UntappdConfig(BuildConfig.UNTAPPDCLIENTID, BuildConfig.UNTAPPDCLIENTSECRET)
}
@Singleton
@Provides
fun retrofit(): Retrofit {
return Retrofit.Builder().baseUrl(BASE_URL).addCallAdapterFactory(RxJava2CallAdapterFactory
.create()).addConverterFactory(GsonConverterFactory.create()).build()
}
@Singleton
@Provides
fun provideUntappedService(retrofit: Retrofit): UntappedService {
return retrofit.create(UntappedService::class.java)
}
}
@Module
class UntappedSearchModule (private val searchView: SearchView) {
@PerFragment
@Provides
fun provideSearchView () = searchView
@PerFragment
@Provides
fun provideSearchInteractor (searchInteractorImpl: SearchInteractorImpl): SearchInteractor {
return searchInteractorImpl
}
@PerFragment
@Provides
fun provideSearchPresenter (searchView: SearchView, searchInteractor: SearchInteractor) : SearchPresenter{
return SearchPresenterImpl(searchView, searchInteractor)
}
}
SearchPresenter
取决于SearchView
中提供的UntappedSearchModule
:
@PerFragment
@Provides
fun provideSearchView () = searchView
提供的和SearchInteractor
:
@PerFragment
@Provides
fun provideSearchInteractor (searchInteractorImpl: SearchInteractorImpl): SearchInteractor {
return searchInteractorImpl
}
SearchInteractorImpl
已在构造函数中注释:
@PerFragment
class SearchInteractorImpl @Inject constructor(private val beerService: UntappedService,
private val config: UntappdConfig) : SearchInteractor {
override fun searchBeers(query: String): io.reactivex.Observable<List<SearchedBeerVO>> {
return beerService.searchBeers(config.clientId, config.clientSecret, query).map({ t -> null })
}
}
取决于来自UntappedService
UntappdConfig
和ServiceModule
@Singleton
@Provides
fun provideUntappedConfig(): UntappdConfig {
return UntappdConfig(BuildConfig.UNTAPPDCLIENTID, BuildConfig.UNTAPPDCLIENTSECRET)
}
@Singleton
@Provides
fun provideUntappedService(retrofit: Retrofit): UntappedService {
return retrofit.create(UntappedService::class.java)
}
Retrofit也在这个模块中。 BeersComponent和BeersFragment是:
@PerFragment
@Subcomponent(modules = [UntappedSearchModule::class])
interface BeersComponent {
fun inject(beersFragment: BeersFragment)
}
class BeersFragment : BaseFragment(), SearchView, AnkoLogger {
override fun injectDependencies(appComponent: AppComponent) {
appComponent.plus(UntappedSearchModule(this)).inject(this)
}
@Inject
lateinit var searchPresenter: SearchPresenter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_beers, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupRecycler()
searchPresenter.search("stella")
}
private fun setupRecycler() {
recyclerSearchResult.layoutManager = LinearLayoutManager(context)
}
override fun displayResults(beers: List<SearchedBeerVO>) {
info("beers: "+beers.size)
recyclerSearchResult.adapter = BeersAdapter(beers)
}
}
BaseFragment:
abstract class BaseFragment : Fragment() {
private val appComponent by lazy {
(activity!!.application as BeerApp).component
}
override fun onAttach(context: Context?) {
super.onAttach(context)
injectDependencies(appComponent)
}
abstract fun injectDependencies (appComponent: AppComponent)
}
---------编辑
我将UntappedSearchModule
更改为:
@Module
class UntappedSearchModule (private val searchView: SearchView) {
@PerFragment
@Provides
fun provideSearchView () = searchView
@PerFragment
@Provides
fun provideSearchPresenterImpl (searchView: SearchView, searchInteractor: SearchInteractor) : SearchPresenterImpl{
return SearchPresenterImpl(searchView, searchInteractor)
}
@Module(includes = arrayOf(UntappedSearchModule::class))
abstract class SearchPresenterModule {
@Binds
abstract fun provideSearchPresenter (searchPresenterImpl: SearchPresenterImpl):SearchPresenter
}
@PerFragment
@Provides
fun provideSearchInteractor (searchInteractorImpl: SearchInteractorImpl): SearchInteractor {
return searchInteractorImpl
}
}
@PerFragment
@Subcomponent(modules = [UntappedSearchModule::class, UntappedSearchModule.SearchPresenterModule::class])
interface BeersComponent {
fun inject(beersFragment: BeersFragment)
}
但同样的问题:
e: /home/alexandre/dev/projetos/gitlab/Cervejas/app/build/tmp/kapt3/stubs/debug/br/com/alexpfx/cervejas/di/AppComponent.java:8: error: [br.com.alexpfx.cervejas.di.beers.BeersComponent.inject(br.com.alexpfx.cervejas.beers.BeersFragment)] br.com.alexpfx.cervejas.search.SearchPresenterImpl cannot be provided without an @Inject constructor or from an @Provides-annotated method.
public abstract interface AppComponent {
^
br.com.alexpfx.cervejas.search.SearchPresenterImpl is injected at
br.com.alexpfx.cervejas.di.UntappedSearchModule.SearchPresenterModule.provideSearchPresenter(searchPresenterImpl)
br.com.alexpfx.cervejas.search.SearchPresenter is injected at
br.com.alexpfx.cervejas.beers.BeersFragment.searchPresenter
br.com.alexpfx.cervejas.beers.BeersFragment is injected at
br.com.alexpfx.cervejas.di.beers.BeersComponent.inject(beersFragment)
---我简化了SearchPresenter以避免使用@Binds并删除了依赖项:
@PerFragment
class SearchPresenterImpl @Inject constructor() :
SearchPresenter {
override fun search(query: String) {
// interactor.searchBeers(query).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread())
// .subscribe({ beers ->
// beers.forEach({ t: SearchedBeerVO? -> println(t) })
// })
}
}
interface SearchPresenter {
fun search (query: String)
}
@PerFragment
@Provides
fun provideSearchPresenterImpl (searchPresenterImpl: SearchPresenterImpl) : SearchPresenter{
return searchPresenterImpl
}
但如果我使用./gradlew build运行它会显示不同的错误:
> Configure project :app
Could not find google-services.json while looking in [src/nullnull/debug, src/debug/nullnull, src/nullnull, src/debug, src/nullnullDebug]
registerResGeneratingTask is deprecated, use registerGeneratedResFolders(FileCollection)
Could not find google-services.json while looking in [src/nullnull/release, src/release/nullnull, src/nullnull, src/release, src/nullnullRelease]
registerResGeneratingTask is deprecated, use registerGeneratedResFolders(FileCollection)
> Task :app:processDebugGoogleServices
Parsing json file: /home/alexandre/dev/projetos/gitlab/Cervejas/app/google-services.json
e: /home/alexandre/dev/projetos/gitlab/Cervejas/app/build/tmp/kapt3/stubs/debug/br/com/alexpfx/cervejas/search/SearchInteractorImpl.java:15: error: cannot find symbol
public io.reactivex.Observable<java.util.List<br.com.alexpfx.cervejas.common.SearchedBeerVO>> searchBeers(@org.jetbrains.annotations.NotNull()
^
symbol: class Observable
location: package io.reactivex
e: /home/alexandre/dev/projetos/gitlab/Cervejas/app/build/tmp/kapt3/stubs/debug/br/com/alexpfx/cervejas/network/UntappedService.java:9: error: cannot find symbol
public abstract io.reactivex.Observable<br.com.alexpfx.cervejas.network.search.SearchResponse> searchBeers(@org.jetbrains.annotations.NotNull()
^
symbol: class Observable
location: package io.reactivex
e: /home/alexandre/dev/projetos/gitlab/Cervejas/app/build/tmp/kapt3/stubs/debug/br/com/alexpfx/cervejas/search/SearchInteractor.java:9: error: cannot find symbol
public abstract io.reactivex.Observable<java.util.List<br.com.alexpfx.cervejas.common.SearchedBeerVO>> searchBeers(@org.jetbrains.annotations.NotNull()
^
symbol: class Observable
location: package io.reactivex
e: /home/alexandre/dev/projetos/gitlab/Cervejas/app/build/tmp/kapt3/stubs/debug/br/com/alexpfx/cervejas/login/LoginActivity.java:8: error: cannot find symbol
private final com.google.firebase.auth.FirebaseAuth firebaseAuth = null;
^
symbol: class FirebaseAuth
location: package com.google.firebase.auth
e: /home/alexandre/dev/projetos/gitlab/Cervejas/app/build/tmp/kapt3/stubs/debug/br/com/alexpfx/cervejas/login/LoginActivity.java:17: error: cannot find symbol
public final com.google.firebase.auth.FirebaseAuth getFirebaseAuth() {
^
symbol: class FirebaseAuth
location: package com.google.firebase.auth
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:kaptDebugKotlin'.
> Compilation error. See log for more details
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 1s
15 actionable tasks: 2 executed, 13 up-to-date
alexandre@alexandre-aero ~/dev/projetos/gitlab/Cervejas $
在Android Studio中,它不会显示这些问题。如果我删除了对Fragment的SearchPresenter依赖,它可以正常工作。
---发现了问题。
出于某种奇怪的原因,错误地使用@Qualifier实现了范围注释:
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
@Scope
annotation class PerFragment