如何在Dagger 2.10中创建自定义作用域模块 [英] How to create custom scoped modules in dagger 2.10

查看:74
本文介绍了如何在Dagger 2.10中创建自定义作用域模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将公司应用迁移到匕首2.10和 AndroidInjector.inject 方法,但是我认为我发现了问题。该应用程序使用自定义范围……例如,登录功能有3个活动(每个活动都有其自己的dagger模块)和一个LoginModule,它负责共享仅应存在于此范围内的单例。因此,在第一个Activity中,我通常执行以下命令:

 公共类LoginActivity扩展了AppCompatActivity {
public void onCreate(捆绑包bla){
LoginActivityComponent activityComponent =(((CustomApplication)getApplicationContext())
.plus(new LoginModule())//生成LoginComponent并将引用保存在CustomApplication
.plus(new LoginActivityModule(this));
activityComponent.inject(this);
...
}

在其他活动中,我只是执行(((CustomApplication)getApplicationContext())。getLoginComponent()。plus(new ForgetPasswordModule())。inject(this)



使用AndroidInjector时如何归档相同的行为?

解决方案

单一子组件作弊



而不是应用程序中的常规实现:

 公共类YourApplication扩展应用程序实现HasActivityInjector {
@Inject DispatchingAndroidInjector< Activity> dispatchingActivityInjector;

@Override
public AndroidInjector< Activity> activityInjector(){
return dispatchingActivityInjector; //始终从Multibindings中获取它。
}
}

只需将活动绑定模块移至LoginComponent并从您的LoginComponent委托给 DispatchingAndroidInjector< Activity> 代替:

  @覆盖
公共AndroidInjector< Activity> activityInjector(){
return getOrCreateLoginComponent()。getActivityInjector();
}

这是正在进行的维护的最小量,但是似乎倒退了,因为您正在预先创建LoginComponent。但是,如果LoginComponent很便宜,并且您是这种样式的唯一子组件,那么一切工作就很好:LoginComponent的注入器可以看到其父级中的多重绑定,因此LoginComponent的ActivityInjector甚至对于父级中的绑定也将始终起作用。 b

由于非登录活动的绑定仍驻留在ApplicationComponent中,因此这些活动将无法使用来自父组件的绑定。但是,否则,这无异于将LoginComponent合并到ApplicationComponent中,这可能不是一个选择,否则您将采用这种方式。



委派AndroidInjector



如果您的LoginComponent创建起来很昂贵,那么作为替代方案,您可以将 getOrCreateLoginComponent()调用移到后面 instanceof 支票:

  @Inject DispatchingAndroidInjector< Activity> dispatchingActivityInjector; 

@Override
public AndroidInjector< Activity> activityInjector(){
返回新的AndroidInjector< Activity>(){
@Override public void inject(Activity活动){
if(LoginActivity的Activity实例
|| OtherLoginActivity的Activity实例) {
getOrCreateLoginComponent()。getActivityInjector()。inject(activity);
} else {
//您也可以在此处链接其他子组件。
dispatchingActivityInjector.inject(活动);
}
}
};
}

这意味着您需要保留一个单独的列表(也许作为字段(在LoginComponent或LoginModule中),这是LoginComponent可以处理的活动,但是如果您希望避免实例化LoginComponent,直到您确定要注入与登录相关的活动,请按照以下方法进行检查。上面的方法也可以很好地扩展到多个子组件,因为您总是在恰好一个 DispatchingAndroidInjector< Activity> 上调用 inject



混合替代



由于地图状态检查可能非常快,因此您也可以为了避免多余的列表,请先与主注射器联系,然后再将其丢弃到登录组件中。当然,如果您具有该样式的多个子组件,这将变得很丑。

  @Inject DispatchingAndroidInjector< Activity> dispatchingActivityInjector; 

@Override
public AndroidInjector< Activity> activityInjector(){
返回新的AndroidInjector< Activity>(){
@Override public void inject(Activity activity){
if(!dispatchingActivityInjector.maybeInject(activity)){
//它不在顶层。开始检查子组件。
getOrCreateLoginComponent()。getActivityInjector()。inject(activity);
}
}
};
}

希望在这三者之间,您不会发现Android注入比宇宙中已知的任何疾病或伤口所造成的痛苦还糟。


I am trying to migrate the company app to dagger 2.10 and the AndroidInjector.inject method, but I think I found a problem. The app uses custom scopes… like the feature Login has 3 activities (each one with it`s own dagger module) and one LoginModule that is responsible for sharing singletons that only should live in this scope. So in the first Activity I used to execute something like:

public class LoginActivity extends AppCompatActivity{
public void onCreate(Bundle bla){
LoginActivityComponent activityComponent = ((CustomApplication) getApplicationContext())
                .plus(new LoginModule()) // generates LoginComponent and save the reference in the CustomApplication
                .plus(new LoginActivityModule(this));
        activityComponent.inject(this);
      ...
}

In the others activities I just execute ((CustomApplication) getApplicationContext()).getLoginComponent().plus(new ForgetPasswordModule()).inject(this)

How can I archive the same behavior when using AndroidInjector ?

解决方案

The single-subcomponent cheat

Rather than the normal implementation in your Application:

public class YourApplication extends Application implements HasActivityInjector {
  @Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

  @Override
  public AndroidInjector<Activity> activityInjector() {
    return dispatchingActivityInjector;  // Always get it from Multibindings.
  }
}

Just move the activity-binding modules to your LoginComponent and delegate to the DispatchingAndroidInjector<Activity> from your LoginComponent instead:

@Override
public AndroidInjector<Activity> activityInjector() {
  return getOrCreateLoginComponent().getActivityInjector();
}

This is the least amount of ongoing maintenance, but it seems pretty backwards, because you're creating your LoginComponent up front. However, if LoginComponent is cheap and is your only subcomponent of this style, then everything works perfectly: LoginComponent's injector can see the multibindings in its parents, so LoginComponent's ActivityInjector will always work even for bindings in the parent.

Because the bindings of non-login activities still reside in the ApplicationComponent, those activities won't be able to use bindings from the parent component. Otherwise, though, this is tantamount to merging your LoginComponent into your ApplicationComponent, which probably isn't an option or else you'd've done it that way.

Delegating AndroidInjector

If your LoginComponent is expensive to create, then as an alternative you could move the getOrCreateLoginComponent() call behind an instanceof check:

@Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

@Override
public AndroidInjector<Activity> activityInjector() {
  return new AndroidInjector<Activity>() {
    @Override public void inject(Activity activity) {
      if (Activity instanceof LoginActivity
          || Activity instanceof OtherLoginActivity) {
        getOrCreateLoginComponent().getActivityInjector().inject(activity);
      } else {
        // You can chain other subcomponents here as well.
        dispatchingActivityInjector.inject(activity);
      }
    }
  };
}

This means that you would need to keep a separate list (maybe as a field in LoginComponent or LoginModule) of activities that LoginComponent can handle, but if you want to avoid instantiating LoginComponent until you're sure that you're injecting a login-related activity, here's how you'd check it. The above approach also scales well to multiple subcomponents, because you're always calling inject on exactly one DispatchingAndroidInjector<Activity> from exactly one Component.

Hybrid alternative

Because the Map presence check is likely pretty fast, you could also avoid that extra list by checking with the main injector first before throwing it to the login component. Of course, that starts to get ugly if you've got multiple subcomponents of that style.

@Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

@Override
public AndroidInjector<Activity> activityInjector() {
  return new AndroidInjector<Activity>() {
    @Override public void inject(Activity activity) {
      if (!dispatchingActivityInjector.maybeInject(activity)) {
        // It's not in the top level. Start checking subcomponents.
        getOrCreateLoginComponent().getActivityInjector().inject(activity);
      }
    }
  };
}

Hopefully, between the three, you won't find Android injection here to be "worse than pain from any disease or wound known in the universe".

这篇关于如何在Dagger 2.10中创建自定义作用域模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆