Внедрение зависимостей — это шаблон проектирования программного обеспечения, направленный на то, чтобы сделать наши приложения слабосвязанными, расширяемыми и обслуживаемыми. Из этого руководства вы узнаете, как обрабатывать внедрение зависимостей с помощью Dagger 2.
Вступление
Когда у вас есть объект, который нуждается или зависит от другого объекта для выполнения своей работы, у вас есть зависимость. Зависимости можно решить, позволив зависимому объекту создать зависимость или попросив фабричный объект создать ее. Однако в контексте внедрения зависимостей зависимости передаются классу, который нуждается в зависимости, чтобы избежать необходимости создания самим классом. Таким образом, вы создаете слабосвязанное и легко обслуживаемое программное обеспечение.
В этом руководстве используется новейшая версия Dagger, Dagger 2 . На момент написания Dagger 2 еще не был официально выпущен и находится на стадии пре-альфа. Тем не менее, он пригоден для использования и стабильный. Вы можете посетить Dagger на GitHub для получения новостей о проекте и возможных датах официального релиза.
Предпосылки
Вам понадобится последняя версия Android Studio, установленная на вашем компьютере для разработки, которую вы можете скачать с сайта Android Developer .
1. Dagger 2 API
Dagger 2 предоставляет ряд специальных аннотаций:
-
@Module
для классов, чьи методы предоставляют зависимости -
@Provides
методы в классах@Module
-
@Inject
для запроса зависимости (конструктор, поле или метод) -
@Component
— это мостовой интерфейс между модулями и инжекцией.
Это наиболее важные аннотации, которые вам необходимо знать, чтобы начать работу с внедрением зависимостей с помощью Dagger 2. Я собираюсь показать вам, как использовать их в простом приложении для Android.
2. Кинжал 2 Рабочий процесс
Чтобы правильно реализовать Dagger 2, вы должны выполнить следующие шаги:
- Определите зависимые объекты и их зависимости.
- Создайте класс с аннотацией
@Module
, используя аннотацию@Provides
для каждого метода, который возвращает зависимость. - Запросите зависимости в ваших зависимых объектах, используя аннотацию
@Inject
. - Создайте интерфейс с
@Component
аннотации@Component
и добавьте классы с аннотацией@Module
созданной на втором шаге. - Создайте объект интерфейса
@Component
чтобы создать экземпляр зависимого объекта с его зависимостями.
Анализ зависимостей переносится со времени выполнения на время компиляции. Это означает, что вы будете уведомлены о возможных проблемах на этапе разработки, в отличие от других библиотек, таких как Guice . Перед использованием библиотеки Dagger 2 необходимо подготовить установку Android Studio для доступа к сгенерированным классам.
3. Настройка среды Android Studio
Шаг 1
Создайте новое приложение с помощью Android Studio и присвойте ему имя. Я назвал свой проект TutsplusDagger .
Шаг 2
Установите минимальный SDK для проекта на API 10, чтобы охватить как можно больше устройств.
Шаг 3
Выберите макет бланка для создаваемой вами деятельности. Для этого урока вам не нужен специальный макет.
Шаг 4
Назовите действие MainActivity
и нажмите « Готово» .
После создания проекта вам необходимо внести несколько изменений в файлы Gradle. Давайте внесем эти изменения в следующем шаге.
4. Настройка Gradle Setup
Шаг 1
Нам нужно изменить файл build.gradle проекта, как показано ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
buildscript {
repositories {
jcenter()
}
dependencies {
classpath ‘com.android.tools.build:gradle:1.0.0’
classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.4’
}
}
allprojects {
repositories {
mavenCentral()
maven{
url ‘https://oss.sonatype.org/content/repositories/snapshots/’
}
}
}
|
Давайте на минутку посмотрим, какие изменения мы внесли:
- зависимости: в этом разделе я добавил плагин, который будет полезен для доступа к коду, сгенерированному Dagger. Если вы этого не сделаете, вы увидите ошибки при обращении к этим новым классам.
- allprojects: Это изменение необходимо, поскольку библиотеки, которые мы собираемся использовать, в настоящее время находятся в пре-альфа, и это единственное доступное место, если вы хотите получить к ним доступ с помощью Maven. Вы можете попробовать загрузить библиотеки Dagger и Dagger Compiler из Sonatype, но это руководство основано на репозиториях Maven.
Шаг 2
Откройте build.gradle в папке приложения вашего проекта и измените его, как показано ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
apply plugin: ‘com.android.application’
apply plugin: ‘com.neenbedankt.android-apt’
android {
compileSdkVersion 21
buildToolsVersion «21.1.2»
defaultConfig {
applicationId «com.androidheroes.tutsplusdagger»
minSdkVersion 10
targetSdkVersion 21
versionCode 1
versionName «1.0»
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’
}
}
}
dependencies {
compile fileTree(dir: ‘libs’, include: [‘*.jar’])
compile ‘com.android.support:appcompat-v7:21.0.3’
compile ‘com.google.dagger:dagger:2.0-SNAPSHOT’
apt ‘com.google.dagger:dagger-compiler:2.0-SNAPSHOT’
provided ‘org.glassfish:javax.annotation:10.0-b28’
}
|
В начале файла я применяю новый плагин. Обязательно поместите новый плагин ( com.neenbedankt.android-apt ) ниже или после плагина Android. Если вы этого не сделаете, то при попытке синхронизировать проект с файлами Gradle будут отображаться ошибки.
В зависимости я добавил:
- библиотека кинжалов
- dagger-компилятор для генерации кода
- javax.annotation для дополнительных аннотаций требуется вне Dagger
После обновления конфигурации Dagger вы можете синхронизировать проект с файлами Gradle, нажав кнопку вверху.
На данный момент у вас есть пустой проект, готовый для использования в вашем приложении. Если вы видите какие-либо ошибки, убедитесь, что вы правильно выполнили вышеуказанные шаги. Теперь мы можем приступить к реализации нашего примера проекта.
5. Реализация Dagger 2
Шаг 1: Определите зависимые объекты
В этом уроке я собираюсь работать с двумя классами: « Vehicle
и « Motor
. Motor
это независимый класс и Vehicle
это зависимый класс. Я собираюсь начать создавать эту модель в новом пакете под названием model
.
Вот как выглядит класс Motor
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.androidheroes.tutsplusdagger.model;
/**
* Created by kerry on 14/02/15.
*/
public class Motor {
private int rpm;
public Motor(){
this.rpm = 0;
}
public int getRpm(){
return rpm;
}
public void accelerate(int value){
rpm = rpm + value;
}
public void brake(){
rpm = 0;
}
}
|
Этот класс имеет только один атрибут rpm
, который я собираюсь изменить с помощью методов accelerate
и brake
. И я проверю текущее значение, используя метод getRpm
.
Вот как выглядит класс Vehicle
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.androidheroes.tutsplusdagger.model;
/**
* Created by kerry on 14/02/15.
*/
public class Vehicle {
private Motor motor;
public Vehicle(Motor motor){
this.motor = motor;
}
public void increaseSpeed(int value){
motor.accelerate(value);
}
public void stop(){
motor.brake();
}
public int getSpeed(){
return motor.getRpm();
}
}
|
В этом классе вы можете видеть, что я не создаю новый объект класса Motor
, хотя я использую его методы. В реальном приложении у этого класса должно быть больше методов и атрибутов, но давайте пока оставим это простым.
Шаг 2: Создать класс @Module
Теперь вам нужно создать класс с аннотацией @Module
. Этот класс будет предоставлять объекты, которые вам понадобятся, с удовлетворенными зависимостями. Для этого вам нужно создать новый пакет (просто чтобы он был в порядке), назвать его module
и добавить в него новый класс следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.androidheroes.tutsplusdagger.module;
import com.androidheroes.tutsplusdagger.model.Motor;
import com.androidheroes.tutsplusdagger.model.Vehicle;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
/**
* Created by kerry on 14/02/15.
*/
@Module
public class VehicleModule {
@Provides @Singleton
Motor provideMotor(){
return new Motor();
}
@Provides @Singleton
Vehicle provideVehicle(){
return new Vehicle(new Motor());
}
}
|
Как я указал в шаге 1 , Vehicle
нуждается в Motor
чтобы работать должным образом. Вот почему вам нужно создать двух провайдеров, одного для Motor
(независимая модель) и другого для Vehicle
(с указанием его зависимости) .
Не забывайте, что каждый поставщик (или метод) должен иметь аннотацию @Provides
а класс должен иметь аннотацию @Module
. Аннотация @Singleton
указывает, что будет только один экземпляр объекта.
Шаг 3: Запрос зависимостей в зависимых объектах
Теперь, когда у вас есть поставщики для ваших различных моделей, вам нужно запросить их. Так же, как Vehicle
нуждается в Motor
, вы должны добавить аннотацию @Inject
в конструкторе Vehicle
следующим образом:
1
2
3
4
|
@Inject
public Vehicle(Motor motor){
this.motor = motor;
}
|
Вы можете использовать аннотацию @Inject
для запроса зависимостей в конструкторе, полях или методах. В этом случае я сохраняю инъекцию в конструкторе.
Шаг 4: Подключение @Modules
с @Inject
Связь между поставщиком зависимостей @Module
и классами, запрашивающими их через @Inject
, осуществляется с помощью @Component
, который является интерфейсом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
package com.androidheroes.tutsplusdagger.component;
import com.androidheroes.tutsplusdagger.model.Vehicle;
import com.androidheroes.tutsplusdagger.module.VehicleModule;
import javax.inject.Singleton;
import dagger.Component;
/**
* Created by kerry on 14/02/15.
*/
@Singleton
@Component(modules = {VehicleModule.class})
public interface VehicleComponent {
Vehicle provideVehicle();
}
|
Рядом с аннотацией @Component
вы должны указать, какие модули будут использоваться — в этом случае я использую VehicleModule
, который мы создали ранее. Если вам нужно использовать больше модулей, просто добавьте их, используя запятую в качестве разделителя.
В интерфейсе добавьте методы для каждого нужного вам объекта, и он автоматически предоставит вам один со всеми удовлетворенными зависимостями. В этом случае мне нужен только объект Vehicle
, поэтому существует только один метод.
Шаг 5: Использование интерфейса @Component
для получения объектов
Теперь, когда у вас есть все готовые соединения, вы должны получить экземпляр этого интерфейса и вызвать его методы для получения нужного вам объекта. Я собираюсь реализовать это в методе onCreate
в MainActivity
следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.androidheroes.tutsplusdagger;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.widget.Toast;
import com.androidheroes.tutsplusdagger.component.Dagger_VehicleComponent;
import com.androidheroes.tutsplusdagger.component.VehicleComponent;
import com.androidheroes.tutsplusdagger.model.Vehicle;
import com.androidheroes.tutsplusdagger.module.VehicleModule;
public class MainActivity extends ActionBarActivity {
Vehicle vehicle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
VehicleComponent component = Dagger_VehicleComponent.builder().vehicleModule(new VehicleModule()).build();
vehicle = component.provideVehicle();
Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
}
}
|
Когда вы пытаетесь создать новый объект интерфейса с аннотацией @Component
, вы должны сделать это с помощью префикса Dagger_<NameOfTheComponentInterface>
, в данном случае Dagger_VehicleComponent
, а затем использовать метод builder
для вызова каждого модуля внутри.
Вы можете видеть, что магия происходит в строке 23. Вы запрашиваете только один объект класса Vehicle
и библиотека отвечает за удовлетворение всех зависимостей, в которых нуждается этот объект. Опять же, вы можете видеть, что нет никакого нового экземпляра любого другого объекта — все управляется библиотекой.
Теперь вы можете запустить приложение и попробовать его на своем устройстве или в эмуляторе. Если вы пошагово выполняли урок, вы увидите сообщение Toast
указанием начального значения или переменной rpm
.
В прикрепленном проекте вы можете увидеть пользовательский интерфейс для класса MainActivity
, в котором вы можете изменять значение переменной rpm
, нажимая кнопки на экране.
Вывод
Внедрение зависимостей — это шаблон, который вам рано или поздно придется внедрить в ваши собственные приложения. С Dagger 2 у вас есть простая в использовании библиотека для его реализации. Я надеюсь, что вы нашли этот урок полезным, и не забудьте поделиться им, если он вам понравился.
Отличный способ стать разработчиком для Android — это использовать шаблоны приложений Android для запуска своих проектов. Вы можете найти шаблоны для игр или других приложений, отдельные элементы пользовательского интерфейса и многое другое.
Или, если вы хотите, чтобы что-то полностью соответствовало вашим спецификациям, вы можете нанять разработчика Android для Envato Studio, чтобы сделать что угодно, от настроек и исправлений ошибок до создания целого приложения с нуля.