{
Dagger2: dependency
injection in Android
Vladimir Tagakov
Hollywood Principle
 Не звоните нам, мы сами вам перезвоним.
Hollywood Principle
 Это паттерн проектирования, а не
библиотека.
 В каждом проекте используется DI
Dependency Injection
Tweeter
Tiwtter
API
Network
Client
Dependency Injection
public class Tweeter { public void tweet(String tweet) {
TwitterApi api = new TwitterApi();
api.postTweet("JakeWharton", tweet);
}
}
public class TwitterApi {
public void postTweet(String user, String tweet) {
OkHttpClient client = new OkHttpClient();
Request request = //...
client.newCall(request).execute();
} }
public class TwitterApi {
private final OkHttpClient client =
new OkHttpClient();
public void postTweet(String user, String tweet) {
Request request = //...
client.newCall(request).execute();
} }
public class TwitterApi {
private final OkHttpClient client =
new OkHttpClient();
public void postTweet(String user, String tweet) {
Request request = //...
client.newCall(request).execute();
} }
public class TwitterApi {
private final OkHttpClient client;
public TwitterApi(OkHttpClient client) { this.client
= client;
}
public void postTweet(String user, String tweet) {
Request request = //...
client.newCall(request).execute();
} }
public class Tweeter { public void tweet(String tweet) {
TwitterApi api = new TwitterApi();
api.postTweet("JakeWharton", tweet);
}
}
public class Tweeter { public void tweet(String tweet) {
TwitterApi api = new TwitterApi(
new OkHttpClient()
);
api.postTweet("JakeWharton", tweet);
}
}
public class Tweeter { public void tweet(String tweet) {
TwitterApi api = new TwitterApi(
new OkHttpClient()
);
api.postTweet("JakeWharton", tweet);
}
}
public class Tweeter { private final TwitterApi api =
new TwitterApi(new OkHttpClient());
public void tweet(String tweet) {
api.postTweet("JakeWharton", tweet);
}
}
public class Tweeter { private final TwitterApi api =
new TwitterApi(new OkHttpClient());
public void tweet(String tweet) {
api.postTweet("JakeWharton", tweet);
}
}
public class Tweeter { private final TwitterApi api =
new TwitterApi(new OkHttpClient());
public Tweeter(String user) { this.user = user; }
public void tweet(String tweet) { api.postTweet(user,
tweet);
}
}
Tweeter tweeter = new Tweeter("JakeWharton"); tweeter.tweet("Hello!");
Tweeter tweeter = new Tweeter("JakeWharton"); tweeter.tweet("Hello!");
Timeline timeline = new Timeline("JakeWharton"); timeline.loadMore(20);
for (Tweet tweet : timeline.get()) {
System.out.println(tweet); }
public class Timeline {
private final List<Tweet> cache =
new ArrayList<>();
private final TwitterApi api =
new TwitterApi(new OkHttpClient());
private final String user;
public Timeline(String user) { this.user = user;
}
public List<Tweet> get() { /* ... */ }
public void loadMore(int amount) { /* ... */ } }
public class Timeline {
private final List<Tweet> cache =
new ArrayList<>();
private final TwitterApi api;
private final String user;
public Timeline(TwitterApi api, String user) { this.user =
user;
this.api = api;
}
public List<Tweet> get() { /* ... */ }
public void loadMore(int amount) { /* ... */ } }
public class Timeline {
private final List<Tweet> cache =
new ArrayList<>();
private final TwitterApi api;
private final String user;
public Timeline(TwitterApi api, String user) { this.user =
user;
this.api = api;
}
public List<Tweet> get() { /* ... */ }
public void loadMore(int amount) { /* ... */ } }
public class Tweeter { private final TwitterApi api =
new TwitterApi(new OkHttpClient());
public Tweeter(String user) { this.user = user; }
public void tweet(String tweet) { api.postTweet(user,
tweet);
}
}
public class Tweeter { private final TwitterApi api;
public Tweeter(TwitterApi api, String user) { this.user =
user;
this.api = api; }
public void tweet(String tweet) { api.postTweet(user,
tweet);
}
}
public class Tweeter { private final TwitterApi api;
public Tweeter(TwitterApi api, String user) { this.user =
user;
this.api = api; }
public void tweet(String tweet) { api.postTweet(user,
tweet);
}
}
Tweeter tweeter = new Tweeter("JakeWharton"); tweeter.tweet("Hello!");
Timeline timeline = new Timeline("JakeWharton"); timeline.loadMore(20);
for (Tweet tweet : timeline.get()) {
System.out.println(tweet); }
OkHttpClient client = new OkHttpClient(); TwitterApi api = new
TwitterApi(client); String user = "Jake Wharton";
Tweeter tweeter = new Tweeter(api, user); tweeter.tweet("Hello!");
Timeline timeline = new Timeline(api, user); timeline.loadMore(20);
for (Tweet tweet : timeline.get()) {
System.out.println(tweet); }
OkHttpClient client = new OkHttpClient(); TwitterApi api = new
TwitterApi(client); String user = "Jake Wharton";
Tweeter tweeter = new Tweeter(api, user); tweeter.tweet("Hello!");
Timeline timeline = new Timeline(api, user); timeline.loadMore(20);
for (Tweet tweet : timeline.get()) { System.out.println(tweet); }
Tweeter
Tiwtter
API
Network
Client
Dependency Injection
Twitter App
•Timeline
•Tweeter
Tiwtter API
Network
Client
Dependency Injection
OkHttpClient client = new OkHttpClient(); TwitterApi api = new
TwitterApi(client); String user = "Jake Wharton";
Tweeter tweeter = new Tweeter(api, user); tweeter.tweet("Hello!");
Timeline timeline = new Timeline(api, user); timeline.loadMore(20);
for (Tweet tweet : timeline.get()) { System.out.println(tweet); }
Как избежать этого?
 Guice
 Dagger (v1)
Немного истории
 Граф объектов проверяется в рантайме
 Большое количество рефлексии
 Медленная инициализация
Guice
 Использование FQCN в качестве ключей при
хранении элементов графа
 Использование рефлексии
Dagger (v1)
 Разработан Java Core Libraries Team
 Compile time анализ графа зависимостей
 Отсутствие рефлексии
 Совместимость с ProGuard
Dagger v2
 @Module + @Provides: для удовлетворения
зависимтостей
 @Inject: для запроса зависимостей
 @Component: соединяет все это вместе
Dagger API
 Модули – классы аннотированные
@Module, содержащие методы
аннотированные @Provides
Удовлетворение
зависимостей
public class NetworkModule {
OkHttpClient provideOkHttpClient() { return new
OkHttpClient();
}
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client); } }
@Module
public class NetworkModule { @Provides
OkHttpClient provideOkHttpClient() { return new
OkHttpClient();
}
@Provides
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client); } }
@Module
public class NetworkModule { @Provides @Singleton
OkHttpClient provideOkHttpClient() { return new
OkHttpClient();
}
@Provides @Singleton
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client); } }
Удовлетворение
зависимостей
OkHttpClient NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Удовлетворение
зависимостей
OkHttpClient NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter NetworkModule#provideTweeter
Timeline NetworkModule#provideTimeline
 Injection в конструктор
 Injection в поле
 Injection в метод
Типы injection
 @Inject на единственном конструкторе
 Параметры конструктора – зависимости
 Зависимости можно хранить в приватных
переменных
 Неявно делает класс доступным для
последующего инжекта
Injection в конструктор
public class TwitterApplication { private final Tweeter tweeter;
private final Timeline timeline;
@Inject public TwitterApplication(Tweeter tweeter, Timeline
timeline) {
this.tweeter = tweeter; this.timeline =
timeline;
}
// ... }
@Module
public class NetworkModule { @Provides @Singleton
OkHttpClient provideOkHttpClient() { return new
OkHttpClient();
}
@Provides @Singleton
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client); } }
public class TwitterApi {
private final OkHttpClient client;
@Inject
public TwitterApi(OkHttpClient client) { this.client
= client;
}
public void postTweet(String user, String tweet) {
Request request = //...
client.newCall(request).execute();
} }
@Singleton
public class TwitterApi {
private final OkHttpClient client;
@Inject
public TwitterApi(OkHttpClient client) { this.client
= client;
}
public void postTweet(String user, String tweet) {
Request request = //...
client.newCall(request).execute();
} }
 @Inject над каждой зависимостью
 Поля не могут быть private или final
 Объект ответственен за процесс инжекта
 Единственный способ инъектить
зависимости в объекты созданием которых
управляем не мы
Injection в поле
public class TwitterActivity extends Activity { @Inject Tweeter tweeter;
@Inject Timeline timeline;
// ... }
 Мост между модулями и получателями
зависимостей
 Инжектор
Components
@Singleton
@Component(modules = { NetworkModule.class,
TwitterModule.class,
})
public interface TwitterComponent {
Tweeter tweeter();
void inject(TwitterActivity activity);
}
public class TwitterActivity extends Activity { @Inject Tweeter tweeter;
@Inject Timeline timeline;
public void onCreate(Bundle savedInstanceState) {
Dagger_TwitterComponent.builder()
.build().inject(this);
}
// ... }
 Linked.in/in/tagakov
Вопросы?

Владимир Тагаков. Dagger2: dependency injection in Android

  • 1.
    { Dagger2: dependency injection inAndroid Vladimir Tagakov
  • 2.
  • 3.
     Не звонитенам, мы сами вам перезвоним. Hollywood Principle
  • 4.
     Это паттернпроектирования, а не библиотека.  В каждом проекте используется DI Dependency Injection
  • 5.
  • 6.
    public class Tweeter{ public void tweet(String tweet) { TwitterApi api = new TwitterApi(); api.postTweet("JakeWharton", tweet); } } public class TwitterApi { public void postTweet(String user, String tweet) { OkHttpClient client = new OkHttpClient(); Request request = //... client.newCall(request).execute(); } }
  • 7.
    public class TwitterApi{ private final OkHttpClient client = new OkHttpClient(); public void postTweet(String user, String tweet) { Request request = //... client.newCall(request).execute(); } }
  • 8.
    public class TwitterApi{ private final OkHttpClient client = new OkHttpClient(); public void postTweet(String user, String tweet) { Request request = //... client.newCall(request).execute(); } }
  • 9.
    public class TwitterApi{ private final OkHttpClient client; public TwitterApi(OkHttpClient client) { this.client = client; } public void postTweet(String user, String tweet) { Request request = //... client.newCall(request).execute(); } }
  • 10.
    public class Tweeter{ public void tweet(String tweet) { TwitterApi api = new TwitterApi(); api.postTweet("JakeWharton", tweet); } }
  • 11.
    public class Tweeter{ public void tweet(String tweet) { TwitterApi api = new TwitterApi( new OkHttpClient() ); api.postTweet("JakeWharton", tweet); } }
  • 12.
    public class Tweeter{ public void tweet(String tweet) { TwitterApi api = new TwitterApi( new OkHttpClient() ); api.postTweet("JakeWharton", tweet); } }
  • 13.
    public class Tweeter{ private final TwitterApi api = new TwitterApi(new OkHttpClient()); public void tweet(String tweet) { api.postTweet("JakeWharton", tweet); } }
  • 14.
    public class Tweeter{ private final TwitterApi api = new TwitterApi(new OkHttpClient()); public void tweet(String tweet) { api.postTweet("JakeWharton", tweet); } }
  • 15.
    public class Tweeter{ private final TwitterApi api = new TwitterApi(new OkHttpClient()); public Tweeter(String user) { this.user = user; } public void tweet(String tweet) { api.postTweet(user, tweet); } }
  • 16.
    Tweeter tweeter =new Tweeter("JakeWharton"); tweeter.tweet("Hello!");
  • 17.
    Tweeter tweeter =new Tweeter("JakeWharton"); tweeter.tweet("Hello!"); Timeline timeline = new Timeline("JakeWharton"); timeline.loadMore(20); for (Tweet tweet : timeline.get()) { System.out.println(tweet); }
  • 18.
    public class Timeline{ private final List<Tweet> cache = new ArrayList<>(); private final TwitterApi api = new TwitterApi(new OkHttpClient()); private final String user; public Timeline(String user) { this.user = user; } public List<Tweet> get() { /* ... */ } public void loadMore(int amount) { /* ... */ } }
  • 19.
    public class Timeline{ private final List<Tweet> cache = new ArrayList<>(); private final TwitterApi api; private final String user; public Timeline(TwitterApi api, String user) { this.user = user; this.api = api; } public List<Tweet> get() { /* ... */ } public void loadMore(int amount) { /* ... */ } }
  • 20.
    public class Timeline{ private final List<Tweet> cache = new ArrayList<>(); private final TwitterApi api; private final String user; public Timeline(TwitterApi api, String user) { this.user = user; this.api = api; } public List<Tweet> get() { /* ... */ } public void loadMore(int amount) { /* ... */ } }
  • 21.
    public class Tweeter{ private final TwitterApi api = new TwitterApi(new OkHttpClient()); public Tweeter(String user) { this.user = user; } public void tweet(String tweet) { api.postTweet(user, tweet); } }
  • 22.
    public class Tweeter{ private final TwitterApi api; public Tweeter(TwitterApi api, String user) { this.user = user; this.api = api; } public void tweet(String tweet) { api.postTweet(user, tweet); } }
  • 23.
    public class Tweeter{ private final TwitterApi api; public Tweeter(TwitterApi api, String user) { this.user = user; this.api = api; } public void tweet(String tweet) { api.postTweet(user, tweet); } }
  • 24.
    Tweeter tweeter =new Tweeter("JakeWharton"); tweeter.tweet("Hello!"); Timeline timeline = new Timeline("JakeWharton"); timeline.loadMore(20); for (Tweet tweet : timeline.get()) { System.out.println(tweet); }
  • 25.
    OkHttpClient client =new OkHttpClient(); TwitterApi api = new TwitterApi(client); String user = "Jake Wharton"; Tweeter tweeter = new Tweeter(api, user); tweeter.tweet("Hello!"); Timeline timeline = new Timeline(api, user); timeline.loadMore(20); for (Tweet tweet : timeline.get()) { System.out.println(tweet); }
  • 26.
    OkHttpClient client =new OkHttpClient(); TwitterApi api = new TwitterApi(client); String user = "Jake Wharton"; Tweeter tweeter = new Tweeter(api, user); tweeter.tweet("Hello!"); Timeline timeline = new Timeline(api, user); timeline.loadMore(20); for (Tweet tweet : timeline.get()) { System.out.println(tweet); }
  • 27.
  • 28.
  • 29.
    OkHttpClient client =new OkHttpClient(); TwitterApi api = new TwitterApi(client); String user = "Jake Wharton"; Tweeter tweeter = new Tweeter(api, user); tweeter.tweet("Hello!"); Timeline timeline = new Timeline(api, user); timeline.loadMore(20); for (Tweet tweet : timeline.get()) { System.out.println(tweet); } Как избежать этого?
  • 30.
     Guice  Dagger(v1) Немного истории
  • 31.
     Граф объектовпроверяется в рантайме  Большое количество рефлексии  Медленная инициализация Guice
  • 32.
     Использование FQCNв качестве ключей при хранении элементов графа  Использование рефлексии Dagger (v1)
  • 33.
     Разработан JavaCore Libraries Team  Compile time анализ графа зависимостей  Отсутствие рефлексии  Совместимость с ProGuard Dagger v2
  • 34.
     @Module +@Provides: для удовлетворения зависимтостей  @Inject: для запроса зависимостей  @Component: соединяет все это вместе Dagger API
  • 35.
     Модули –классы аннотированные @Module, содержащие методы аннотированные @Provides Удовлетворение зависимостей
  • 36.
    public class NetworkModule{ OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  • 37.
    @Module public class NetworkModule{ @Provides OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } @Provides TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  • 38.
    @Module public class NetworkModule{ @Provides @Singleton OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } @Provides @Singleton TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  • 39.
  • 40.
  • 41.
     Injection вконструктор  Injection в поле  Injection в метод Типы injection
  • 42.
     @Inject наединственном конструкторе  Параметры конструктора – зависимости  Зависимости можно хранить в приватных переменных  Неявно делает класс доступным для последующего инжекта Injection в конструктор
  • 43.
    public class TwitterApplication{ private final Tweeter tweeter; private final Timeline timeline; @Inject public TwitterApplication(Tweeter tweeter, Timeline timeline) { this.tweeter = tweeter; this.timeline = timeline; } // ... }
  • 44.
    @Module public class NetworkModule{ @Provides @Singleton OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } @Provides @Singleton TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  • 45.
    public class TwitterApi{ private final OkHttpClient client; @Inject public TwitterApi(OkHttpClient client) { this.client = client; } public void postTweet(String user, String tweet) { Request request = //... client.newCall(request).execute(); } }
  • 46.
    @Singleton public class TwitterApi{ private final OkHttpClient client; @Inject public TwitterApi(OkHttpClient client) { this.client = client; } public void postTweet(String user, String tweet) { Request request = //... client.newCall(request).execute(); } }
  • 47.
     @Inject надкаждой зависимостью  Поля не могут быть private или final  Объект ответственен за процесс инжекта  Единственный способ инъектить зависимости в объекты созданием которых управляем не мы Injection в поле
  • 48.
    public class TwitterActivityextends Activity { @Inject Tweeter tweeter; @Inject Timeline timeline; // ... }
  • 49.
     Мост междумодулями и получателями зависимостей  Инжектор Components
  • 50.
    @Singleton @Component(modules = {NetworkModule.class, TwitterModule.class, }) public interface TwitterComponent { Tweeter tweeter(); void inject(TwitterActivity activity); }
  • 51.
    public class TwitterActivityextends Activity { @Inject Tweeter tweeter; @Inject Timeline timeline; public void onCreate(Bundle savedInstanceState) { Dagger_TwitterComponent.builder() .build().inject(this); } // ... }
  • 52.