Инъекция зависимостей на Android с RoboGuice
Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)
Введение
RoboGuice, также называемый Google Guice на Android, представляет собой простую в использовании платформу для внедрения зависимостей, которая может сделать разработку Android более интуитивной и удобной. Используя этот фреймворк, вы можете значительно сократить количество написанного вами кода для выполнения общих задач, таких как инициализация различных ресурсов, доступ к системным службам Android и обработка событий.
В этом уроке я расскажу вам, как максимально использовать RoboGuice 3 в ваших проектах на Android.
1. Понимание инъекции зависимостей
Традиционно, если объект зависит от чего-то, его собственная ответственность заключается в удовлетворении этой зависимости. В более простых терминах, если экземпляр класса A зависит от экземпляра класса B, разработчик обычно должен вызывать конструктор класса B внутри кода класса A. Это, очевидно, приводит к более тесной связи между этими двумя классами.
Инъекция зависимостей - это шаблон проектирования, в котором объекты полагаются на внешний код, который обычно называют инжектором зависимости, чтобы удовлетворить их зависимости. Это означает, что если объект зависит от других объектов, он не должен знать, как создавать или инициализировать эти объекты. Это уменьшает связь между объектами и приводит к более модульному, более легкому изменению кода и менее сложному тестированию.
Таким образом, используя инъекцию зависимостей, вы можете в значительной степени избавиться от конструкторов и фабричных методов в бизнес-логике вашего проекта.
2. Как работает RoboGuice
Google Guice - это среда, которая упрощает создание, настройку и использование инжектора зависимостей в ваших проектах Java. RoboGuice основывается на Google Guice и поставляется с предустановленной инъекцией зависимостей для Android. Проще говоря, RoboGuice знает, как инициализировать различные объекты Android, как получать ссылки на различные ресурсы приложения и многое другое.
RoboGuice использует аннотации Java, которые представляют собой не что иное, как метаданные, встроенные в код Java, для определения того, что нужно туда вводить. Более ранние версии RoboGuice использовались для обработки аннотаций с использованием API Java Reflection во время выполнения, и их часто критиковали за то, что они были медленными. RoboGuice 3, однако, поставляется с RoboBlender, компилятором-обработчиком аннотаций, который значительно улучшает производительность RoboGuice.
3. Настройка RoboGuice
Прежде чем использовать RoboGuice, вы должны добавить его как compile
зависимость в файле build.gradle вашего модуля app. Поскольку он доступен в репозитории по умолчанию для Android Studio, jcenter, для этого требуется только одна строка кода.
compile 'org.roboguice:roboguice:3.0.1'
Чтобы повысить производительность RoboGuice, рекомендуется также добавить RoboBlender, обработчик аннотации, в качестве provided
зависимости.
provided 'org.roboguice:roboblender:3.0.1'
Чтобы иметь возможность использовать аннотации RoboGuice в ваших действиях в Android, их классы должны расширять RoboActivity
вместо Activity
. Аналогичным образом, если вы хотите использовать аннотации внутри службы Android, ее класс должен расширять RoboService
вместо Service
.
4. Связывание макетов с действиями
Обычно вы используете метод setContentView
и передаете ему ресурс макета, чтобы установить макет Activity
. RoboGuice предлагает альтернативные способы сделать то же самое с аннотацией @ContentView
.
Например, вот как вы применили бы макет, определенный в XML-файле с именем activity_main.xml, к RoboActivity
под названием MainActivity:
@ContentView(R.layout.activity_main) public class MainActivity extends RoboActivity { }
5. Инъекция отображений
Если вы думаете, что с помощью метода findViewById
и тайп-кастинга объекта View
, который он возвращает, это слишком много работы, то вы можете использовать аннотацию @InjectView
RoboGuice.
Например, рассмотрим следующий макет:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/email" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/okay" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
Чтобы инициализировать два виджета пользовательского интерфейса, определенные в XML в RoboActivity
, вы можете написать следующее:
@InjectView(R.id.email) private TextView email; @InjectView(R.id.okay) private Button okay;
6. Инъекция ресурсов
Доступ к ресурсам вашего приложения с использованием API Android включает в себя множество разных классов и функций. Например, для извлечения Drawable
необходимо использовать ContextCompat.getDrawable
. Чтобы получить Animation
, вам нужно будет использовать AnimationUtils.loadAnimation
.
Аннотации @InjectResource
от RoboGuice предлагают более последовательный способ получения всех типов ресурсов. Следующий фрагмент кода показывает вам, как вводить ColorStateList
, ресурс Drawable
, String
и Animation
:
@InjectResource(R.color.red) private ColorStateList red; @InjectResource(R.drawable.square) private Drawable square; @InjectResource(R.string.hello) private String hello; @InjectResource(R.anim.fade) private Animation fade;
7. Инъекция системных сервисов
Чтобы получить ссылку на системные службы Android, такие как PowerManager
или Vibrator
, вы можете использовать аннотацию @Inject
вместо метода getSystemService
. Например, вот как вы получите ссылку на PowerManager
:
@Inject private PowerManager pm;
8. Инъекция дополнений
Вы можете использовать аннотацию @InjectExtra
, чтобы ввести дополнительные функции, которые были переданы RoboActivity
. В следующем фрагменте кода вводится дополнение, ключ которого EMAIL_ADDRESS:
@InjectExtra("EMAIL_ADDRESS") private String email;
Обратите внимание, что @InjectExtra
вызовет ошибку времени выполнения, если дополнения не будет. Если дополнительный параметр является optional
, вы должны включить необязательный флаг, значение которого равно true
, чтобы избежать ошибки.
@InjectExtra(value = "EMAIL_ADDRESS", optional = true) String email;
9. Инъекция собственных классов
До сих пор мы вводили элементы, специфичные для Android SDK. Чтобы ввести собственные классы, вы должны использовать аннотацию @Inject
. @Inject
ведет себя так же, как ключевое слово Java new
, и вам не нужно вносить какие-либо изменения в класс, чтобы сделать его инъективным, если у него есть конструктор по умолчанию. Например, рассмотрим следующий класс:
public class Employee { public Employee() { Log.d("RG", "Hello"); } }
Чтобы ввести экземпляр класса Employee
, вы должны использовать следующий код:
@Inject Employee p; // equivalent to new Employee()
10. Использование пользовательских поставщиков
Если вам нужен более тонкий контроль над тем, что вводится при использовании @Inject
, вам необходимо создать своих собственных поставщиков.
Давайте создадим простого провайдера, который возвращает случайное число каждый раз, когда @Inject
используется для инициализации Integer
.
Шаг 1. Создание провайдера
Поставщик - это просто класс, который реализует интерфейс Provider
. Поэтому создайте новый класс MyRandomNumberProvider, который реализует Provider
и отменяет его метод get
.
public class MyRandomNumberProvider implements Provider<Integer> { @Override public Integer get() { } }
Как вы могли догадаться, возвращаемое значение метода get
- это то, что будет введено при использовании @Inject
. Чтобы вернуть случайное целое число, добавьте следующий код к методу get
:
// Returns a random integer between 0 and 999 return (int)(Math.random()*1000);
Шаг 2. Создание модуля
Чтобы иметь возможность использовать свой пользовательский поставщик, вам нужно создать для него модуль. Модуль - это класс, который расширяет класс AbstractModule
. Внутри модуля вы переопределяете метод configure
и указываете, какой класс должен использовать поставщик, используя методы bind
и toProvider
.
Чтобы создать модуль для MyRandomNumberProvider
, создайте новый класс Java MyRandomNumberModule и добавьте к нему следующий код:
public class MyRandomNumberModule extends AbstractModule { @Override public void configure() { // Bind Integer to MyRandomNumberProvider bind(Integer.class) .toProvider(MyRandomNumberProvider.class); } }
Шаг 3: зарегистрируйте модуль
Чтобы RoboGuice узнал о вашем модуле, вы должны зарегистрировать его в AndroidManifest.xml вашего приложения, используя тег meta-data
. Атрибут name
тега должен быть установлен в roboguice.modules, а его атрибут value
должен содержать имя класса модуля.
<meta-data android:name = "roboguice.modules" android:value="com.github.hathibelagal.roboguicetutorial.MyRandomNumberModule" />
Теперь поставщик готов. На этом этапе, если вы аннотируете Integer
с @Inject
, он будет инициализирован случайным числом.
@Inject Integer random1; // Initialized to a random number @Inject Integer random2; // Initialized to another random number
11. Работа с синглтонами
Если вы являетесь разработчиком, который предпочитает использовать singleton для обмена данными между несколькими действиями и услугами, вы можете использовать аннотации @Singleton
и @Inject
для упрощения кода.
Добавив аннотацию @Singleton
к классу, вы можете позволить RoboGuice знать, что он не должен создавать более одного экземпляра класса. Следующий код создает синглтон под названием MySingleton:
@Singleton class MySingleton { }
Теперь вы можете использовать аннотацию @Inject
, чтобы ввести синглтон в свои классы. Например, вот как вы вводите MySingleton
:
@Inject MySingleton singleton;
12. Наблюдение за событиями
Используя аннотацию @Observes
, вы можете наблюдать различные события, связанные с Activity
. Это означает, что вам не нужно переопределять методы onCreate
, onResume
и другие методы жизненного цикла класса Activity
.
Следующий код показывает вам, как аннотация @Observes
может использоваться как альтернатива переопределению методов onCreate
и onDestroy
:
public class MainActivity extends RoboActivity { // Called when the Activity is created public void initialize(@Observes OnCreateEvent e) { // Initialization code goes here } // Called when the Activity is destroyed public void cleanup(@Observes OnDestroyEvent e) { // Clean up code goes here } }
Заключение
В этом уроке вы узнали, как использовать RoboGuice, чтобы сделать ваш код более кратким и читаемым. При этом вы также узнали, как использовать аннотации Java и шаблон инъекции зависимостей.
Чтобы узнать больше о RoboGuice, я рекомендую просмотреть его вики на GitHub.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weekly