【问题标题】:Dagger 2: Inject 2 different scopes into one objectDagger 2:将 2 个不同的作用域注入到一个对象中
【发布时间】:2018-11-20 17:53:30
【问题描述】:

在有人开始将此问题标记为重复之前,让我说我已经检查过这个post,但它并没有解决我的问题。

正如标题所说,我需要在另一个对象中注入来自不同范围的两个对象。 假设我们有下一种情况:

我们有一个让用户注册的屏幕,然后在同一个屏幕中,我们根据用户会话执行一些操作(例如:进行一些同步)。

对于我的项目,我计划使用子组件。到目前为止,我有基于此post 的下一个代码(简化):

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {

  static AppComponent init(MyApplication application) {
    return DaggerAppComponent.builder()
        .appModule(new AppModule(application))
        .build();
  }

  UserSessionComponent plusUserSessionComponent(UserSessionModule userSessionModule);

  void inject(MyApplication application);
}

@Module
public class AppModule {

  private MyApplication myApplication;

  public AppModule(@NonNull MyApplication myApplication) {
    this.myApplication = myApplication;
  }

  @Provides
  @Singleton
  public AppSignUp provideAppSignUp() {
    return new AppSignUp();
  }
}

@UserSessionScope
@Subcomponent(modules = {UserSessionModule.class})
public interface UserSessionComponent {

  static UserSessionComponent init(AppComponent appComponent,
      UserSession userSession) {
    return appComponent.plusUserSessionComponent(userSession);
  }

  void inject(MyApplication myApplication);
}

@Module
public class UserSessionModule {

  private UserSession userSession;

  public UserSessionModule(@NonNull UserSession userSession) {
    this.userSession = userSession;
  }

  @Provides
  @UserSessionScope
  public UserSessionSyncHelper provideUserSession(UserSession userSession) {
    return new UserSessionSyncHelper(userSession);
  }


  @Provides
  @UserSessionScope
  public UserSessionSync provideUserSession(UserSessionSyncHelper userSessionSyncHelper) {
    return new UserSessionSync(userSessionSyncHelper);
  }
}

现在,为了简单起见,假设我有一个组件(活动、视图模型、演示者或其他)将具有这两个依赖项:

public MyActivity extends AppCompatActivity {

  @Inject
  AppSignUp appSignUp;

  @Inject
  UserSessionSync userSessionSync;

  public void onCreate(Bundle savedInstanceState) {
    //to inject appSignUp
    MyApplication.getAppComponent().inject(this);
  }

  public onUserCreated(UserSession userSession) {
    //to inject userSessionSync
    MyApplication.getUserSessionComponent().inject(this);
  }
}

我的问题是 Dagger 在第一次注入时会抱怨,因为 AppModile 没有 userSessionSync。所以问题是,我该如何解决这个问题? Dagger 有适合这种场景的功能吗?

到目前为止,我只能想到下一个解决方案:

使 UserSessionSync 独立于 Dagger 框架和内部

public class UserSessionSync {
  @Inject
  UserSessionSyncHelper userSessionSyncHelper;

  public UserSessionSync(){
    MyApplication.getUserSessionComponent().inject(this)
  }
}

在我看来,这不是处理这个问题的好方法。

【问题讨论】:

    标签: android dagger-2


    【解决方案1】:

    尝试使用 Dagger-Android,效果很好。 AppSignUp 也不需要模块。 @Inject constructor() 和 @Singleton 会做到这一点。在底层,它使用子组件。

    @Module
    abstract class AppModule {
    
        @Module
        companion object {
    
            @JvmStatic
            @Provides
            @Singleton
            fun providesAppSignUp() = AppSignUp()
    
        }
    }
    
    @Singleton
    @Component( modules = [AndroidSupportInjectionModule::class, ActivityBindingModule::class, AppModule::class] )
    interface AppComponent : AndroidInjector<MainApplication>
    
    @Module
    interface ActivityBindingModule {
    
        @UserScope
        @ContributesAndroidInjector( modules = [MainActivityModule::class] )
        fun mainActivity() : MainActivity
    }
    
    @Module
    abstract class MainActivityModule {
    
        @Module
        companion object {
    
            @JvmStatic
            @Provides
            @UserScope
            fun providesUserSession() = UserSession()
        }
    }
    
    class UserSession
    
    class AppSignUp
    
    @Scope
    annotation class UserScope
    
    class MainApplication : DaggerApplication() {
    
        @Inject
        lateinit var appSignUp : AppSignUp
    
        override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
            return DaggerAppComponent.builder().build()
        }
    
    }
    
    class MainActivity : DaggerAppCompatActivity() {
    
        @Inject
        lateinit var appSignUp: AppSignUp
    
        @Inject
        lateinit var appSignUp1: AppSignUp
    
        @Inject
        lateinit var userSession: UserSession
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
        }
    }
    

    【讨论】:

    • 感谢您的回答,但您的代码显示了如何在活动中注入对象,这不是我的问题。实际上,我正在使用它,但我没有将它添加到此示例中。在您的代码中,虽然 userSession 是使用 userScope 定义的,但它从活动的一开始就被注入,并且它作为一个单例工作,另一方面,在我的示例中,userSession 具有自定义范围,它应该被注入当应用程序有一个新的用户会话时(使用我编写的代码解决了该部分,尽管我不知道如何将一个类注入具有不同范围的不同对象)。
    • 看看github.com/frogermcs/GithubClient。 GithubClientApplication 具有用户管理功能,并具有在用户注销时重置的显式逻辑(有点)。
    • @LeandroOcampo 在这种情况下,UserComponent 是 AppComponent 的子组件,并且对父绑定具有可见性。在 UserComponent 上调用注入会负责注入 AppComponent 提供的绑定。
    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    相关资源
    最近更新 更多