Dagger2和Android

Gab*_*tin 5 android dagger-2

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

我想要做的是拥有一堆可以在我的应用程序中使用的注入就绪对象,即SharedPreferences,Network对象(OkHttp,Retrofit,Picasso ...),以及RxJava的EventBus和SchedulerProvider对象.

这个样本似乎提供了我需要的一切,但我无法掌握一些概念.

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

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

他们使用UserScope注释定义自己的范围.既然不能使用@Singleton,这是否意味着该对象不会是Singleton?范围如何真正影响DI?似乎他们只宣布一个命名范围没有更多的影响,但我不确定.

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

Epi*_*rce 8

组件应该是"大型DI提供商",为特定范围提供一切.

例如,您可以拥有一个SingletonComponentwith @Singletonscope,其中添加了每个模块,其中至少有一个@Singleton作用域提供者方法.

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

您可以为每个模块定义配置方法.

public interface DatabaseComponent {
    RealmHolder realmHolder();
}

public interface NetworkingComponent{
    OkHttpClient okHttpClient();
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下你会有

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

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

例如,

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

    @Provides
    @Singleton
    Retrofit retrofit(OkHttpClient okHttpClient) {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将@Singleton范围想象为Spring将为您提供的大型DI容器.


您还可以使用带@Inject注释的构造函数提供类的实例.这可以从组件中接收任何类,该类能够从该范围组件的模块中的提供者方法实例化它(当然还有未组装的依赖项).

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

要么

@Singleton
public class MyMapper {
    @Inject
    RealmHolder realmHolder;

    @Inject
    OkHttpClient okHttpClient;

    @Inject
    public MyMapper() {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,这将在组件中可用,您甚至可以为它提供配置方法,使其在组件依赖项中可继承:

@Singleton 
@Component(modules={...})
public interface SingletonComponent {
    MyMapper myMapper();
}
Run Code Online (Sandbox Code Playgroud)

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

例如,您可以继承所有@Singleton作用域组件,但是仍然可以为该新作用域添加新的作用域依赖项,例如@ActivityScope.

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
Run Code Online (Sandbox Code Playgroud)

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


  • 子组件:

.

@ActivityScope
@Subcomponent(modules={MainActivityModule.class})
public interface MainActivityComponent {
    MainPresenter mainPresenter();
}
Run Code Online (Sandbox Code Playgroud)

然后可以在其父作用域组件中创建它:

@Singleton 
@Component(modules={...})
public interface SingletonComponent {
    MainActivityComponent mainActivityComponent(MainActivityModule module);
}
Run Code Online (Sandbox Code Playgroud)

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

SingletonComponent singletonComponent = DaggerSingletonComponent.create();
MainActivityComponent mainActivityComponent = singletonComponent.mainActivityComponent(new MainActivityModule(mainActivityHolder));
Run Code Online (Sandbox Code Playgroud)
  • 组件依赖:

.

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

为此,您必须在超组件组件中指定提供方法.

然后你可以这样实例化:

SingletonComponent singletonComponent = DaggerSingletonComponent.create();
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
                       .singletonComponent(singletonComponent)
                       .mainActivityModule(new MainActivityModule(mainActivityHolder))
                       .build();
Run Code Online (Sandbox Code Playgroud)

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

  • @Inject 带注释的构造函数参数
  • @Inject具有带@Inject注释的构造函数的类上带注释的字段
  • @Component提供方法
  • 通过组件中定义的手动字段注入方法(对于无法使用带@Inject注释的构造函数创建的类)

手动现场注入可能发生在MainActivity您自己不创建的类上.

手动场注入仅注入您正在注入的特定类.基类没有自动注入,他们需要调用.inject(this)组件.

它的工作原理如下:

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

然后你可以这样做:

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);       
    }
}
Run Code Online (Sandbox Code Playgroud)