Dagger2和Android [英] Dagger2 and Android

查看:81
本文介绍了Dagger2和Android的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的应用程序中实现Dagger依赖注入,但是我很难理解它是如何工作的,特别是来自Spring的DI更加容易并且更具声明性.

I am trying to implement Dagger Dependency Injection into my app but I am having a hard time understanding how it works, especially coming from Spring where DI was much easier and much more declarative.

我想要做的是有一堆可以在我的应用程序中使用的随时可以使用的对象,即SharedPreferences,Network对象(OkHttp,Retrofit,Picasso ...),EventBus和SchedulerProvider对象.用于RxJava.

What I want to do is have a bunch of inject-ready objects that can be used throughout my app, that is the SharedPreferences, the Network objects (OkHttp, Retrofit, Picasso...), and EventBus and a SchedulerProvider object for RxJava.

此示例似乎提供了我需要的一切但是我在掌握一些概念时遇到了麻烦.

This sample seems to offer everything I need but I am having trouble grasping some concepts.

在上一页中引用的其他示例中,他们创建了一个使用Retrofit对象的GithubService.在NetModule中提供.为此,他们创建了这样的GithubComponent:

In this other sample referenced in the previous page they create a GithubService that uses the Retrofit object provided in the NetModule. For that they create a GithubComponent like this:

@UserScope
@Component(dependencies = NetComponent.class, modules = GitHubModule.class)
public interface GitHubComponent {
    void inject(MainActivity activity);
}

他们正在使用UserScope注释定义其自己的范围.由于无法使用@Singleton,这是否意味着该对象将不是Singleton?范围如何真正影响DI?看来他们只是在声明命名作用域而已,但不再起作用,但我不确定.

They are using a UserScope annotation that defines its own scope. Since @Singleton cannot be used, does this mean that the object will not be a Singleton? How do scopes really affect the DI? It seems they are only declaring a named-scope with no more effect, but I'm not sure.

此外,我的应用是使用带有片段的活动构建的.我必须为我的应用程序中的每个片段创建一个组件吗?即我需要在整个应用程序中使用我的REST api服务,是否需要为使用它们的每个屏幕声明一个组件?这样会增加所需的样板代码数量,因此听起来不太干净.

Also, my app is built using Activities with Fragments. Do I have to create a Component for every Fragment in my app? i.e. I need to use my REST api services all throughout the app, do I have to declare a Component for every screen using them? This raises the amount of boilerplate code required and thus sounds not very clean.

推荐答案

组件应成为大型DI提供程序",为特定范围提供所有内容.

Components ought to be the "big DI provider" that provides everything for a specific scope.

例如,您可能拥有一个范围为@SingletonSingletonComponent,其中添加了每个模块的每个模块都具有至少一个@Singleton范围内的提供者方法.

For example, you could have a SingletonComponent with @Singleton scope that has every single module added to it that has at least one @Singleton scoped provider method.

@Singleton
@Component(modules={NetworkingModule.class, DatabaseModule.class, MapperModule.class, UtilsModule.class})
public interface SingletonComponent {
    // provision methods
    OkHttpClient okHttpClient();
    RealmHolder realmHolder();
    // etc.
}

您可以按模块定义供应方法.

You can have the provision methods defined per module.

public interface DatabaseComponent {
    RealmHolder realmHolder();
}

public interface NetworkingComponent{
    OkHttpClient okHttpClient();
}

在这种情况下,您将拥有

In which case you'd have

@Singleton
@Component(modules={NetworkingModule.class, DatabaseModule.class, MapperModule.class, UtilsModule.class})
public interface SingletonComponent 
      extends NetworkingComponent, DatabaseComponent, MapperComponent, UtilsComponent {
    // provision methods inherited
}



在模块中,您可以指定工厂方法(提供者方法"),该方法指定如何创建特定类型的依赖项.



In a Module, you can specify a factory method ("provider method") that specifies how to create a particular type of dependency.

例如,

@Module
public class NetworkingModule {
    @Provides
    @Singleton
    OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()./*...*/.build();
    }

    @Provides
    @Singleton
    Retrofit retrofit(OkHttpClient okHttpClient) {
        // ...
    }
}

您可以将@Singleton范围想象为Spring会给您的大DI容器.

You can imagine the @Singleton scope as the big DI container that Spring would have given you.

您还可以使用带@Inject注释的构造函数提供类的实例.这样可以从组件接收任何类,这些类都可以从该范围组件的模块内的提供者方法实例化它(当然,也包括无作用域的依赖项).

You can also provide instances of the class using @Inject annotated constructor. This can receive any class from the component that is able to instantiate it from provider methods within that scoped component's modules (and unscoped dependencies, of course).

@Singleton
public class MyMapper {
    @Inject
    public MyMapper(RealmHolder realmHolder, OkHttpClient okHttpClient) { // totally random constructor for demo
    }
}

@Singleton
public class MyMapper {
    @Inject
    RealmHolder realmHolder;

    @Inject
    OkHttpClient okHttpClient;

    @Inject
    public MyMapper() {
    }
}

这将在组件中可用,您甚至可以为其设置方法以使其在组件依赖项中可继承:

Then this will be available in the component, you can even make provision method for it to make it inheritable in component dependencies:

@Singleton 
@Component(modules={...})
public interface SingletonComponent {
    MyMapper myMapper();
}



使用Dagger2,您还可以另外创建子范围的组件",该子组件继承从给定作用域的组件提供的所有依赖项.



With Dagger2, you can also additionally create "subscoped components", that inherit all dependencies provided from a component of a given scope.

例如,您可以继承所有@Singleton范围内的组件,但是每个新范围仍然可以具有新的范围内依赖项,例如@ActivityScope.

For example, you can inherit all @Singleton scoped components, but you can still have new scoped dependencies per that new scope, such as @ActivityScope.

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}

然后,您可以使用子组件或组件依赖项来创建子范围的组件.

Then, you can create subscoped components using either subcomponents, or component dependencies.

  • 子组件:

.

@ActivityScope
@Subcomponent(modules={MainActivityModule.class})
public interface MainActivityComponent {
    MainPresenter mainPresenter();
}

然后可以在其父范围的组件中创建它:

Then this can be created in its parent scoped component:

@Singleton 
@Component(modules={...})
public interface SingletonComponent {
    MainActivityComponent mainActivityComponent(MainActivityModule module);
}

然后,您可以使用单例组件来实例化它:

Then you can use the singleton component to instantiate this:

SingletonComponent singletonComponent = DaggerSingletonComponent.create();
MainActivityComponent mainActivityComponent = singletonComponent.mainActivityComponent(new MainActivityModule(mainActivityHolder));


  • 组件依赖性:

    • Component dependency:
    • .

      @ActivityScope
      @Component(dependencies={SingletonComponent.class}, modules={MainActivityModule.class})
      public interface MainActivityComponent extends SingletonComponent {
          MainPresenter mainPresenter();
      }
      

      为此,您必须必须在超级作用域组件中指定设置方法.

      For this to work, you must specify provision methods in the superscoped component.

      然后您可以像这样实例化

      Then you can instantiate this like so:

      SingletonComponent singletonComponent = DaggerSingletonComponent.create();
      MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
                             .singletonComponent(singletonComponent)
                             .mainActivityModule(new MainActivityModule(mainActivityHolder))
                             .build();
      



      因此,在Dagger2中,您可以通过以下方式获取依赖关系:



      In Dagger2, you can therefore obtain dependencies either via:

      • @Inject带注释的构造函数参数
      • 具有@Inject注释的构造函数的类上的
      • @Inject注释的字段
      • 通过@Component设置方法
      • 通过组件中定义的手动字段注入方法(对于无法使用@Inject带注释的构造函数创建的类)
      • @Inject annotated constructor parameters
      • @Inject annotated fields on classes with @Inject annotated constructor
      • from @Component provision methods
      • via manual field injection method defined in component (for classes you can't create using @Inject annotated constructor)

      对于您自己没有创建的类,例如MainActivity,可能会发生手动字段注入.

      Manual field injection can happen for classes like MainActivity, that you yourself don't create.

      手动字段注入仅注入您要注入的特定类.基类不会自动注入,它们需要在组件上调用.inject(this).

      Manual field injection injects only the specific class that you are injecting. Base-classes don't get automatically injected, they need to call .inject(this) on component.

      它是这样的:

      @ActivityScope
      @Subcomponent(modules={MainActivityModule.class})
      public interface MainActivityComponent {
          void inject(MainActivity mainActivity);
      }
      

      然后您可以执行以下操作:

      Then you can do:

      public class MainActivity extends AppCompatActivity {
          @Override
          public void onCreate(Bundle bundle) {
              super.onCreate(bundle);
              MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
                                .singletonComponent(getSingletonComponent())
                                .mainActivityModule(new MainActivityModule(this))
                                .build(); // ensure activity `holder` instead, and retain component in retained fragment or `non-configuration instance`
              mainActivityComponent.inject(this);       
          }
      }
      

      这篇关于Dagger2和Android的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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