2016-11-11 76 views
4

我试图在我的应用程序中实现Dagger依赖注入,但我很难理解它是如何工作的,特别是来自Spring的DI更容易和更具说明性。Dagger2和Android

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

This sample似乎提供我需要的一切,但我无法理解一些概念。

在上一页中引用的other sample中,他们创建了一个使用NetModule中提供的Retrofit对象的GithubService。为此,他们创建一个如下的GithubComponent:

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

他们正在使用UserScope注释来定义自己的作用域。由于不能使用@Singleton,这是否意味着对象不会是Singleton?示波器如何真正影响DI?看起来他们只声明了一个没有更多效果的命名范围,但我不确定。

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

回答

6

组件应该是“大DI提供商”,提供一切为了一个特定的范围。

例如,您可以有一个SingletonComponent@Singleton作用域,每个添加的模块至少有一个@Singleton作用域提供程序方法。

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

您可以为每个模块定义供应方法。

public interface DatabaseComponent { 
    RealmHolder realmHolder(); 
} 

public interface NetworkingComponent{ 
    OkHttpClient okHttpClient(); 
} 

在这种情况下,你不得不

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


在一个模块中,可以指定一个工厂方法(“提供方法”),指定了如何创建一个特定的依赖类型。

例如,

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

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

你可以想象@Singleton范围为春节会给你很大的DI容器。


您还可以使用@Inject带注释的构造函数提供该类的实例。这可以接收组件中的任何类,该组件可以通过该范围组件的模块中的提供者方法实例化该组件(当然还包括无范围的依赖关系)。

@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() { 
    } 
} 

那么这将是组件中可用,你甚至可以做出规定的方法为它使可继承的组件的依赖:

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


随着Dagger2,你也可以添加盟友创建“subscoped组件”,它继承了从给定范围的组件提供的所有依赖项。

例如,您可以继承所有@Singleton作用域组件,但您仍然可以为每个新作用域创建新的作用域依赖项,例如@ActivityScope

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

然后,您可以创建使用两种子,或组件的依赖subscoped组件。


  • 成分:

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

那么这可以在其父创建范围的组件:

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

然后你就可以使用单独组件来实例化这样的:

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

  • 组件的依赖:

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

对于这个工作,你必须指定在superscoped部件供给方法。

然后就可以像这样实例化这个:

  • @Inject注释构造参数
  • @Inject

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


    在Dagger2,可以因此无论是通过获得的依赖关系clas上的注释字段与@Inject SES注释构造

  • 从通过在组件中定义的手动场注入法@Component规定方法
  • (用于类不能创建使用@Inject注释的构造函数)

手册字段注射可能发生像类MainActivity,你自己并没有创建。

手动现场注入仅注入要注入的特定类别。基类不会自动注入,他们需要在组件上调用.inject(this)

它的工作原理是这样的:

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

然后,你可以这样做:

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);  
    } 
} 
+0

这使得它更清晰,我仍然有一些疑虑,但我会尝试从这里解决它。我唯一的问题是 - 我仍然需要为我的应用程序中的每个片段/活动创建一个组件/子组件? –

+0

你不**有**,我做了3个应用程序只使用一个'@ Singleton'组件,没有其他组件。 – EpicPandaForce

0

1)

由于@Singleton不能使用,这意味着该对象将 不是一个Singleton?

GitHubComponent组件具有@UserScope范围,如果你想在这个范围内声明单例,它应该是@Singleton。

2)

如何范围真正影响DI?看起来他们只声明 命名范围没有任何效果,但我不确定。

javax docs

甲范围注释适用于包含可注射 构造函数的类和支配喷射器如何重新使用类型的实例。 默认情况下,如果不存在范围注释,则注入器将创建一个实例(通过注入该类型的构造函数),将该实例用于一次注入,然后将其忽略。如果存在范围注释,则注射器可保留该实例以便在稍后的注射中可能重用。

3)

我一定要创建一个组件在我的应用程序的每个片段?

您可以创建一次,实例化并存储在您的Application对象中,然后在每次需要注入某些东西(如果您的片段或活动)时进行查询。

检查this example

+0

但是那又有什么GitHubComponent作为一个子的目的是什么?为什么不创建一个包含所有实例的ApplicationComponent并在整个应用程序中使用它? –