Dagger2:如果没有@Inject构造函数或@Provides注释方法,将无法提供

问题描述 投票:0回答:1

我刚刚重构了匕首代码,使其可扩展,并将所有核心内容移动到名为di的单独模块中。

现在,当我尝试将依赖项注入应用程序模块时,我得到了这个:

[Dagger/MissingBinding] retrofit2.Retrofit cannot be provided without an @Inject constructor or an @Provides-annotated method.
public abstract interface ResetPasswordComponent {
                ^
      retrofit2.Retrofit is injected at
          com.sahra.oms.ibshop.features.resetpassword.di.ResetPasswordNetworkModule.providerResetPasswordAPI(retrofit)
      com.sahra.oms.ibshop.data.remote.service.ResetPasswordService is injected at
          com.sahra.oms.ibshop.data.repisotory.nationalid.UniqueRepositoryImpl(resetPasswordService)
      com.sahra.oms.ibshop.data.repisotory.nationalid.UniqueRepositoryImpl is injected at
          com.sahra.oms.ibshop.features.resetpassword.di.ResetPasswordModule.bindUniqueIdRepository(uniqueRepositoryImpl)
      com.sahra.oms.ibshop.data.repisotory.nationalid.UniqueIdRepository is injected at
          com.sahra.oms.ibshop.features.resetpassword.uniqueid.CheckUniqueIDViewModel(repository)
      com.sahra.oms.ibshop.features.resetpassword.uniqueid.CheckUniqueIDViewModel is injected at
          com.sahra.oms.ibshop.features.resetpassword.di.ResetPasswordModule.bindCheckIdViewModel(checkUniqueIDViewModel)
      java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
          com.sahra.oms.ibishop.di.util.ViewModelFactory(viewModelsMap)
      com.sahra.oms.ibishop.di.util.ViewModelFactory is injected at
          com.sahra.oms.ibshop.di.ViewModelBuilder.bindViewModelFactory(arg0)
      androidx.lifecycle.ViewModelProvider.Factory is injected at
          com.sahra.oms.ibshop.features.resetpassword.newpassword.NewPasswordFragment.viewModelFactory
      com.sahra.oms.ibshop.features.resetpassword.newpassword.NewPasswordFragment is injected at
          com.sahra.oms.ibshop.features.resetpassword.di.ResetPasswordComponent.inject(com.sahra.oms.ibshop.features.resetpassword.newpassword.NewPasswordFragment)

ResetPasswordService只是一个Retrofit接口。

这是我的代码:

AppComponent

@Singleton
@AppScope
@Component
interface AppComponent {


    fun provideContextComponent(): ContextComponent
    fun provideNetworkComponent(): NetworkComponent
    fun provideSharedPrefComponent(): SharedPreferencesComponent

    fun inject(app: Application)

    @Component.Factory
    interface Factory {

        fun create(
            @BindsInstance
            context: ContextComponent,
            @BindsInstance
            network: NetworkComponent,
            @BindsInstance
            sharedPrefs: SharedPreferencesComponent
        ): AppComponent
    }
}

NetworkComponent:

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class NetworkScope


@NetworkScope
@Component(
    dependencies = [ContextComponent::class],
    modules = [OkHttpModule::class, AuthBinderModule::class]
)
interface NetworkComponent {

    fun provideOkHttp(): OkHttpClient
    fun provideRetrofit(): Retrofit
    fun provideGson(): GsonConverterFactory

}

OkHttpModule:

@Module
object OkHttpModule {
    private const val BASE_URL = "base_url"

    @Provides
    @JvmStatic
    fun provideLoggingInterceptor(): HttpLoggingInterceptor {
        return HttpLoggingInterceptor(
            HttpLoggingInterceptor.Logger { message -> Log.d("<<<network>>>", message) }).apply {
            level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
        }
    }

    @Provides
    @JvmStatic
    fun provideChuckInterceptor(app: Application): ChuckInterceptor = ChuckInterceptor(app)

    @Provides
    @JvmStatic
    fun provideOkhttpCache(app: Application): Cache =
        Cache(app.cacheDir, 50_000_000)

    @Provides
    @NetworkScope
    @JvmStatic
    fun provideClient(
        loggingInterceptor: HttpLoggingInterceptor,
        chuckInterceptor: ChuckInterceptor,
        authInterceptor: Interceptor,
        cache: Cache
    ): OkHttpClient {
        return OkHttpClient.Builder()
            .cache(cache)
            .addInterceptor(loggingInterceptor)
            .addInterceptor(authInterceptor)
            .addInterceptor(chuckInterceptor)
            .build()
    }

    @Provides
    @NetworkScope
    @JvmStatic
    fun provideGson() = Gson()


    @Provides
    @JvmStatic
    fun provideGsonConverter(gson: Gson) = GsonConverterFactory.create(gson)

    @Provides
    @NetworkScope
    @JvmStatic
    fun provideRetrofit(
        gsonConverterFactory: GsonConverterFactory,
        client: Lazy<OkHttpClient>
    ): Retrofit = Retrofit.Builder()
        .callFactory { request -> client.get().newCall(request) }
        .baseUrl(BASE_URL)
        .addConverterFactory(gsonConverterFactory)
        .build()
}

这是我尝试注入依赖项的方式:

@FeatureScope
@Component(
    dependencies = [AppComponent::class],
    modules = [
        ResetPasswordNetworkModule::class,
        ResetPasswordModule::class,
        ViewModelBuilder::class
    ]
)
interface ResetPasswordComponent {
    fun inject(newPasswordFragment: NewPasswordFragment)
    fun inject(checkUniqueIDFragment: CheckUniqueIDFragment)

    @Component.Builder
    interface Builder {
        fun coreComponent(appComponent: AppComponent): Builder
        fun build(): ResetPasswordComponent
    }
}
@Module
abstract class ResetPasswordModule {

    @Binds
    abstract fun bindResetPasswordRepository(resetPasswordRepositoryImpl: ResetPasswordRepositoryImpl): ResetPasswordRepository

    @Binds
    abstract fun bindUniqueIdRepository(uniqueRepositoryImpl: UniqueRepositoryImpl): UniqueIdRepository

    @Binds
    @IntoMap
    @ViewModelKey(CheckUniqueIDViewModel::class)
    abstract fun bindCheckIdViewModel(checkUniqueIDViewModel: CheckUniqueIDViewModel): ViewModel


    @Binds
    @IntoMap
    @ViewModelKey(NewPasswordViewModel::class)
    abstract fun bindNewPasswordViewModel(newPasswordViewModel: NewPasswordViewModel): ViewModel
}
@Module
object ResetPasswordNetworkModule {
    @Provides
    @JvmStatic
    @FeatureScope
    fun provideUserAPI(
        retrofit: Retrofit
    ): ResetPasswordService = retrofit.create(ResetPasswordService::class.java)
}

这是我的存储库代码:

class ResetPasswordRepositoryImpl @Inject constructor(
    private val resetPasswordService: ResetPasswordService
) : ResetPasswordRepository {
}

片段:

class NewPasswordFragment{
    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
}
class NewPasswordViewModel @Inject constructor(
    private val repository: ResetPasswordRepository
)

提前感谢。

android dagger-2
1个回答
0
投票

您的应用程序组件工厂看起来像这样:

    fun create(
        @BindsInstance
        context: ContextComponent,
        @BindsInstance
        network: NetworkComponent,
        @BindsInstance
        sharedPrefs: SharedPreferencesComponent
    ): AppComponent

这提供对NetworkComponent实例的访问,因此需要@Provides的任何@Binds@InjectNetworkComponent都可以得到一个。它确实not,但是可以直接访问NetworkComponent的对象图。

NetworkComponent已经公开了Retrofit,因此如果可以访问该组件,则可以肯定获得一个。但是,此过程不是自动的,并且在您的设置中需要使用@Provides方法。

@Provides
fun provideRetrofit(component: NetworkComponent): Retrofit = component.provideRetrofit()

这是需要解决的。一种更好的方法是使NetworkComponent成为AppComponent的依赖项(或仅使用其模块并完全删除网络组件),然后在Retrofit中公开AppComponent

// using multiple scoped dependencies requires Dagger 2.27
@AppScope
@Component(dependencies = [ContextComponent::class, NetworkComponent::class, SharedPreferencesComponent::class])
interface AppComponent {
    fun provideRetrofit(): Retrofit
    // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.