Статьи

Внедрение зависимостей с помощью Dagger 2 на Android

Внедрение зависимостей — это шаблон проектирования программного обеспечения, направленный на то, чтобы сделать наши приложения слабосвязанными, расширяемыми и обслуживаемыми. Из этого руководства вы узнаете, как обрабатывать внедрение зависимостей с помощью Dagger 2.

Когда у вас есть объект, который нуждается или зависит от другого объекта для выполнения своей работы, у вас есть зависимость. Зависимости можно решить, позволив зависимому объекту создать зависимость или попросив фабричный объект создать ее. Однако в контексте внедрения зависимостей зависимости передаются классу, который нуждается в зависимости, чтобы избежать необходимости создания самим классом. Таким образом, вы создаете слабосвязанное и легко обслуживаемое программное обеспечение.

В этом руководстве используется новейшая версия Dagger, Dagger 2 . На момент написания Dagger 2 еще не был официально выпущен и находится на стадии пре-альфа. Тем не менее, он пригоден для использования и стабильный. Вы можете посетить Dagger на GitHub для получения новостей о проекте и возможных датах официального релиза.

Вам понадобится последняя версия Android Studio, установленная на вашем компьютере для разработки, которую вы можете скачать с сайта Android Developer .

Dagger 2 предоставляет ряд специальных аннотаций:

  • @Module для классов, чьи методы предоставляют зависимости
  • @Provides методы в классах @Module
  • @Inject для запроса зависимости (конструктор, поле или метод)
  • @Component — это мостовой интерфейс между модулями и инжекцией.

Это наиболее важные аннотации, которые вам необходимо знать, чтобы начать работу с внедрением зависимостей с помощью Dagger 2. Я собираюсь показать вам, как использовать их в простом приложении для Android.

Чтобы правильно реализовать Dagger 2, вы должны выполнить следующие шаги:

  1. Определите зависимые объекты и их зависимости.
  2. Создайте класс с аннотацией @Module , используя аннотацию @Provides для каждого метода, который возвращает зависимость.
  3. Запросите зависимости в ваших зависимых объектах, используя аннотацию @Inject .
  4. Создайте интерфейс с @Component аннотации @Component и добавьте классы с аннотацией @Module созданной на втором шаге.
  5. Создайте объект интерфейса @Component чтобы создать экземпляр зависимого объекта с его зависимостями.

Анализ зависимостей переносится со времени выполнения на время компиляции. Это означает, что вы будете уведомлены о возможных проблемах на этапе разработки, в отличие от других библиотек, таких как Guice . Перед использованием библиотеки Dagger 2 необходимо подготовить установку Android Studio для доступа к сгенерированным классам.

Создайте новое приложение с помощью Android Studio и присвойте ему имя. Я назвал свой проект TutsplusDagger .

Шаг 1 Введите имя для проекта

Установите минимальный SDK для проекта на API 10, чтобы охватить как можно больше устройств.

Шаг 2 Выберите минимальный SDK

Выберите макет бланка для создаваемой вами деятельности. Для этого урока вам не нужен специальный макет.

Шаг 3 Выберите шаблон для проекта

Назовите действие MainActivity и нажмите « Готово» .

Шаг 4 Введите имя для действия

После создания проекта вам необходимо внести несколько изменений в файлы Gradle. Давайте внесем эти изменения в следующем шаге.

Нам нужно изменить файл 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.

Откройте 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, нажав кнопку вверху.

Синхронизировать проект с файлами оценок

На данный момент у вас есть пустой проект, готовый для использования в вашем приложении. Если вы видите какие-либо ошибки, убедитесь, что вы правильно выполнили вышеуказанные шаги. Теперь мы можем приступить к реализации нашего примера проекта.

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

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

Теперь, когда у вас есть поставщики для ваших различных моделей, вам нужно запросить их. Так же, как Vehicle нуждается в Motor , вы должны добавить аннотацию @Inject в конструкторе Vehicle следующим образом:

1
2
3
4
@Inject
public Vehicle(Motor motor){
    this.motor = motor;
}

Вы можете использовать аннотацию @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 , поэтому существует только один метод.

Теперь, когда у вас есть все готовые соединения, вы должны получить экземпляр этого интерфейса и вызвать его методы для получения нужного вам объекта. Я собираюсь реализовать это в методе 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, чтобы сделать что угодно, от настроек и исправлений ошибок до создания целого приложения с нуля.