【问题标题】:Hilt not finding service刀柄找不到服务
【发布时间】:2021-12-09 16:21:09
【问题描述】:

我正在尝试理解 HILT,我正在创建一个示例项目,我习惯于创建模块和组件,但现在有了一个 Hilt,有 InstallIn(),也许我必须和他们一起玩和以前一样。例如,我习惯于为每个功能创建一个模块:

LoginModule(包含:ViewModel、活动/片段、数据源、用例等...) ProductModule(包含:ViewModel、活动/片段、数据源、用例等...)

从现在开始,我用刀柄创建了一个NetworkModule

@Module
@InstallIn(ApplicationComponent::class)
object NetworkModule {

    @Provides
    fun provideRetrofit(httpClient: OkHttpClient): Retrofit =
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(httpClient)
            .build()

    @Provides
    fun provideOkHttpClient(
        httpLoggingInterceptor: HttpLoggingInterceptor,
        @ErrorInterceptorOkHttpClient errorInterceptor: Interceptor,
    ): OkHttpClient = OkHttpClient()
        .newBuilder()
        .addInterceptor(httpLoggingInterceptor)
        .addInterceptor(errorInterceptor)
        .build()


    @ErrorInterceptorOkHttpClient
    @Provides
    fun provideErrorInterceptor(): Interceptor = ErrorInterceptor()

    @Provides
    fun provideHttpLogginInterceptor(): HttpLoggingInterceptor {
        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = when {
            BuildConfig.DEBUG -> HttpLoggingInterceptor.Level.BODY
            else -> HttpLoggingInterceptor.Level.NONE
        }
        return loggingInterceptor
    }

    @Provides
    fun provideMyService(retrofit: Retrofit): MyService =
        retrofit.create(MyService::class.java)
}

然后我有了这个功能,或者说应用程序的一部分,它是我想从现在开始显示一些东西的主页,我已经创建了这个:


@Module
@InstallIn(FragmentComponent::class)
object MainActivityModule {
    @Provides
    fun proviceDataSource(
        myService: MyService,
        myMapper: MyMapper,
    ): MyDatasource = MyDatasourceImpl(myService, myMapper)

    @Provides
    fun provicesMyMapper(): MyMapper = MapperImpl()

}

在我的活动中,我添加了

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

在 Fragment 中,我什么都没有,也许这就是我做错的事情?

以及何时使用 ApplicationComponent SingletonComponent 等? 因为我使用的是 dagger(不是 dagger-android),所以我有一个 ComponentFactory,我将所有这些组件作为(LoginComponent,GoogleMapComponent,ReferalCodeComponent)所有这些都是一个功能(谈论多模块项目),我正在创建这些组件的工厂,现在使用 Hilt 的方式如何?

【问题讨论】:

  • 这里有什么问题?有什么错误吗?

标签: android kotlin dagger dagger-hilt


【解决方案1】:

在使用多个模块时,如果按照我的想法,我会在一个库中定义多个模块,并提供给接口模块使用。

您的问题是如何使用您在接口模块中定义的工厂方法?关于这一点,我不太明白你的问题。

如果您使用 MVVM 架构,您可以将这些组件注入到 ViewModel 中。这些组件(如 LoginComponent)提供的 Flow 可以在 ViewModel 中访问。当然,通过 ViewModel 注入的参数也可以方便的访问到你提供的组件的对应方法。

下面是我的 Demo 中的 ViewModel:

@HiltViewModel
class NickNameViewModel @Inject constructor(
    private val repo: DataRepo,
    application: Application,
): AndroidViewModel(application) {

fun updateUserNickName(
        userId: String,
        userKey: String,
        userNickName: String,
        resultCallBack: (Boolean, String) -> Unit = {_, _ -> },
    ) {
        viewModelScope.launch {
            repo.updateUserInfo(
                userId = userId,
                userKey = userKey,
                userNickName = userNickName,
            ).collect {
                 //.....
                }
            }
        }
    }

}

在上面的ViewModel中,DetaRepo组件是通过构造注入的方式注入到ViewModel中的。

DataRepo 中提供的方法可以在方法 updateUserNickName 中轻松访问。

下面是Fragment中ViewModel的代码:

@AndroidEntryPoint
class NickNameModifyFragment: Fragment(R.layout.nick_name_modify_fragment) {

    companion object {
        const val nickNickNameResult = "nickNickNameResult"
    }

    private var _binding: NickNameModifyFragmentBinding? = null

    private val viewModel by viewModels<NickNameViewModel>()

}

需要注意的是,如果Hilt在Fragment的ViewModel中,还需要在attach Activity中添加@AndroidEntryPoint注解。

希望能给你带来好运。

【讨论】:

    【解决方案2】:

    如果您使用的是 SingletonComponent,那么使用 @Provides 注释,您还应该要求使用 @singleton 注释

    @Module
    @InstallIn(SingletonComponent::class)
    object AppModule {
        @Singleton @Provides
        fun provideServiceGenerator(
            context: Context
        ) = ServiceGenerator(context)
    }
    

    同样对于 FragmentComponent 你需要用 @Provides @FragmentScoped

    当我读到你提到 UseCase 和其他东西时,你必须检查 hilt viewModel 因为它会自动为你生成大量样板代码并根据活动或片段生命周期处理依赖关系

    @Module
    @InstallIn(ViewModelComponent::class)
    object ViewModelModule {
    
        //repo
        @Provides
        @ViewModelScoped
        fun providesTicketsRepo(
            checkOutApi: CheckOutApi
        )= TicketsRepo(checkOutApi)
    }
    

    @HiltViewModel
    class TicketsAndCouponViewModel
    @Inject constructor(
        val ticketsRepo: TicketsRepo
    ) : ViewModel() { /****/}
    

    内部片段和活动

    val viewModel by viewModels<TicketsAndCouponViewModel>()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-09
      • 1970-01-01
      • 2020-10-20
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多