Dagger.android 用户作用域

6
我正在尝试使用https://google.github.io/dagger/android创建UserScope。我有@Singleton@ActivityScope@FragmentScope@UserScopeAppComponent
@Singleton
@Component(
  modules = [
    AndroidSupportInjectionModule::class,
    ActivityBindingModule::class,
    AppModule::class,
    ApiModule::class
  ]
)
interface AppComponent {

  fun inject(application: Application)

  fun createUserComponent(): UserComponent.Builder

  @Component.Builder
  interface Builder {

    @BindsInstance
    fun application(app: Application): Builder

    fun apiModule(module: ApiModule): Builder

    fun build(): AppComponent
  }
}

UserComponent:

@UserScope
@Subcomponent(
  modules = [UserModule::class]
)
interface UserComponent {

  @Subcomponent.Builder
  interface Builder {
    @BindsInstance
    fun user(user: User): Builder

    fun build(): UserComponent
  }
}

UserModule:

@Module
class UserModule {

  @UserScope
  @Provides
  fun provideUser(user: User): User = user
}

以下是我在成功登录后创建UserComponent的方法:

 private fun createSession(user: User) {    
      userComponent = appComponent.createUserComponent().user(user).build()
  }

我还有一个UserManager,它会触发与User注入构造函数参数相关的问题。

@UserScope
class SomeManager @Inject constructor(
    private val apiService: ApiService,
    private val user: User
) {}

错误信息:Error:[dagger.android.AndroidInjector.inject(T)] 未使用@Inject构造函数或@Provides注释方法提供domain.model.authorize.User。 di.modules.MainActivityBindingModule_ContributeUserFragment.UserFragmentSubcomponent范围为@di.scopes.FragmentScope,不得引用具有不同作用域的绑定:@di.scopes.UserScope类domain.managers.SomeManager。
我想创建@UserScope来管理相关的ApiManagers生命周期。
@Module
class UserFragmentModule {

  @Provides
  @FragmentScope
  fun provideViewModelFactory(someModule: SomeModule) = UserFragmentViewModelFactory(someModule)
}

ContributesAndroidInjector逻辑:

@Module
interface ActivityBindingModule {

  @ActivityScope
  @ContributesAndroidInjector(modules = [SplashModule::class])
  fun contributeSplashActivity(): SplashActivity

  @ActivityScope
  @ContributesAndroidInjector(modules = [SignInModule::class])
  fun contributeAuthorizeActivity(): Activity

  @ActivityScope
  @ContributesAndroidInjector(modules = [MainModule::class])
  fun contributeMainActivity(): MainActivity
}


@Module(includes = [MainActivityBindingModule::class])
class MainModule


@Module
interface MainActivityBindingModule {

  @FragmentScope
  @ContributesAndroidInjector(modules = [UserFragmentModule::class])
  fun contributeUserFragment(): UserFragment
}

能否分享一下 UserFragmentSubcomponent - azizbekian
@azizbekian,这是自动生成的类。但无论如何,这里是它的链接 https://codeshare.io/21Zwl0 - Near1999
@azizbekian,有什么建议吗?)) - Near1999
你能分享一下 UserModule 吗?它应该有一个依赖项 SomeManager,并且作用域为 @UserScope。但是,只要 UserFragmentSubcomponent 的作用域为 @FragmentScope,这是不可能的。其次,也不存在一个提供 User 对象的方法。 - azizbekian
@azizbekian,文本中存在UserModule。我已经添加了UserFragmentModule,它位于@FragmentScope下,但使用SomeManager作为依赖项。我尝试将UserFragment作为UserComponent的子组件,但在Application类中注入DispatchingAndroidInjector时出现问题,因为我需要同时拥有@Singleton@UserScope的注入器。 - Near1999
请提供您的“应用程序”代码以及您想要注入用户的“Activity”或“Fragment”。 - Benjamin
2个回答

0

您正在尝试注入一个仅在@UserScope中提供的User实例到@FragmentScope中。

基本上,规则是每当您需要注入User时,您需要处于@UserScope中。

您需要在所有类似的地方将@FragmentScope更改为@UserScope注释。

根据您发布的内容,我相信它在这里:

@Module
class UserFragmentModule {

  @Provides
  @UserScope
  fun provideViewModelFactory(someModule: SomeModule) = UserFragmentViewModelFactory(someModule)
}

你需要将UserFragmentModule移动到UserComponent中:

@UserScope
@Subcomponent(
  modules = [UserModule::class, UserFragmentModule::class]
)
interface UserComponent {

你还需要将 application.userComponent 注入到你的 UserFragment 中。
这里有一篇关于子组件的好 文章。我建议你阅读它以获得全面的理解。
另一个选项,我不确定是否可行,但也许你可以直接用你的 application.userComponent 注入你的 UserFragment。

不确定“你还需要使用application.userComponent注入到UserFragment中”与“你可以直接使用application.userComponent注入到UserFragment中”有何不同。 - arekolek

-1

我认为你的问题在于作用域的错误使用。 作用域可以帮助我们处理注入项的生命周期,以防止在整个应用程序生命周期中保留不需要的对象。

enter image description here

并且看一下这张图片:

enter image description here

你的模块应该与你的组件在同一个作用域中。 例如,在您的AppComponent中,您有一个具有ActivityScopeActivityBindingModule。为什么这样做?

我认为最好有一个activityComponent,它依赖于appComponent。如果你的activityComponent在更高级别的组件(appComponent)中有一些依赖关系,那么首先你需要添加该组件的依赖关系。(dependencies=[AppComponent::class])。其次,您需要使用返回所需依赖项对象的方法在appComponent中公开所需的依赖项。最后,在Dagger wire upping中,您应该调用appComponent并调用活动模块。(我将在示例中展示这一点) 所以,你只需要像这样的activityComponent

@ActivityScope
@Component(modules = [ActivityBindingModule::class],dependencies= [ AppComponent::class])
interface activityComponent {
.
.
.

这是我的Java示例,展示了如何连接appComponentactivityComponent

@Singleton
@Component(modules = {ApplicationModule.class ,ServicesModule.class})
public interface ApplicationComponent {

void inject(ImicoApplication imicoApplication);

// exposed for child-components.
Context getContext();
Application getApplication();
CompanyService getCompanyService();
CategoryService getCategoryService();
RatingService getRatingService();
NewsService getNewsService();
AuthorizationManager getAuthorizationManager();
}

这是activityComponent

@ActivityScope
@Component(dependencies = {ApplicationComponent.class},modules = {SearchActivityModule.class})
public interface SearchserviceComponent {

    void inject (SearchFragment searchFragment);
}

在SearchFragment中进行以下的连线:

DaggerSearchserviceComponent.builder()
        .applicationComponent(((ImicoApplication) getActivity().getApplication()).getApplicationComponent())
        .searchActivityModule(new SearchActivityModule(this)).build().inject(this);

如果在SearchFragment中需要使用CompanyService,只需注入它即可,它由applicationComponent提供和公开。

例如,在您的AppComponent中,您有一个具有ActivityScope的ActivityBindingModule。为什么这样做? - 不是这样的,该范围适用于生成的子组件(用于注入活动)。 - arekolek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接