2016-11-11 2 views
4

Я пытаюсь внедрить Injection Dependency Injection в мое приложение, но мне сложно понять, как это работает, особенно из Spring, где DI был намного проще и гораздо более декларативным.Dagger2 и Android

Что я хочу сделать, это иметь кучу объектов, готовых к инъекции, которые можно использовать во всем моем приложении, то есть SharedPreferences, Сетевые объекты (OkHttp, Retrofit, Picasso ...) и EventBus и SchedulerProvider объект для RxJava.

This sample, кажется, предлагает все, что мне нужно, но у меня возникли проблемы с пониманием некоторых концепций.

В этом other sample, упомянутом на предыдущей странице, создается GithubService, который использует объект Retrofit, предоставленный в модуле NetModule. Для этого они создают 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 Scoped метод провайдера.

@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 вы также можете добавить создайте «подкопированные компоненты», которые наследуют все зависимости, предоставляемые от компонента данной области.

Например, вы можете наследовать все облачные компоненты @Singleton, но у вас все еще есть новые зависимые области для этой новой области, такие как @ActivityScope.

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

Затем вы можете создавать подкопные компоненты, используя либо подкомпоненты, либо зависимости компонентов.


  • Подкомпонент:

.

@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 компоненте.

Тогда вы можете создать экземпляр этого так:

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


В Dagger2, вы можете таким образом получить зависимости либо через:

  • @Inject аннотированных параметров конструктора
  • @Inject аннотированные поля на класах сес с @Inject аннотированным конструктором
  • из @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 не могут быть использованы, это означает, что объект будет не быть Синглтон?

Компонент GitHubComponent имеет область @UserScope, это должно быть @Singleton, если вы хотите объявить Singletons в этой области.

2)

Как прицелы действительно влияют на DI? Кажется, они объявляют только с именем-scope без эффекта, но я не уверен.

От javax docs

Области применения аннотаций относится к классу, содержащему инъецируемый конструктор и управляет тем, как инжектор повторно экземпляры типа. По умолчанию, если аннотация отсутствует, инжектор создает экземпляр (путем ввода конструктора типа), использует экземпляр для одной инъекции и затем забывает об этом. Если имеется аннотация для области видимости, то инжектор может сохранить экземпляр для возможного повторного использования в более поздней версии .

3)

Должен ли я создать компонент для каждого фрагмента в моем приложении?

Вы можете создать его один раз, создать экземпляр и сохранить его в своем приложении, а затем запросить его каждый раз, когда вам нужно что-то вводить, если ваш фрагмент или активность.

Проверить this example

+0

Но что цель GitHubComponent быть подкомпонентой? Почему бы не создать один ApplicationComponent со всеми экземплярами и использовать его во всем приложении? –

Смежные вопросы