- Dependency injection on Android with Hilt
- Jetpack’s recommended library for DI
- Hilt in action
- Comes with Jetpack support!
- Start using Hilt
- Getting started with Hilt
- Documentation
- For Dagger users
- Codelabs
- Sample code
- Cheat sheet
- Android Dependency Injection With Koin
- Prerequisites
- What exactly is dependency injection
- Getting started with Koin
- Creating project components
- Creating a Koin module
- Starting Koin
- Conclusion
- About the author
- Want to learn more about the EngEd Program?
- Dagger 2 для начинающих Android разработчиков. Внедрение зависимостей. Часть 1
- Серия статей
- Ранее в цикле статей
- Что такое внедрение зависимостей (dependency injection, DI)
- Стратегия решения проблемы сильных связей (hard dependency) или проблемы Белых Ходоков
- Метод внедрения зависимостей
- Пример 1
- Сценарий 1. Без использования внедрения зависимостей
- Анализируем War
- Резюме
Dependency injection on Android with Hilt
Jetpack’s recommended library for DI
Dependency injection (DI) is a technique widely used in programming and well suited to Android development, where dependencies are provided to a class instead of creating them itself. By following DI principles, you lay the groundwork for good app architecture, greater code reusability, and ease of testing. Have you ever tried manual dependency injection in your app? Even with many of the existing dependency injection libraries today, it requires a lot of boilerplate code as your project becomes larger, since you have to construct every class and its dependencies by hand, and create containers to reuse and manage dependencies.
By following DI principles, you lay the groundwork for good app architecture, greater code reusability, and ease of testing.
The new Hilt library defines a standard way to do DI in your application by providing containers for every Android class in your project and managing their lifecycles automatically for you.
Hilt is built on top of the popular DI library Dagger so benefits from the compile time correctness, runtime performance, scalability, and Android Studio support that Dagger provides. Due to this, Dagger’s seen great adoption on 30% of top 10k apps of the Google Play Store. However, because of the compile time code generation, expect a build time increase.
Since many Android framework classes are instantiated by the OS itself, there’s an associated boilerplate when using Dagger in Android apps. Unlike Dagger, Hilt is integrated with Jetpack libraries and Android framework classes and removes most of that boilerplate to let you focus on just the important parts of defining and injecting bindings without worrying about managing all of the Dagger setup and wiring. It automatically generates and provides:
- Components for integrating Android framework classes with Dagger that you would otherwise need to create by hand.
- Scope annotations for the components that Hilt generates automatically.
- Predefined bindings and qualifiers.
Best of all, as Dagger and Hilt can coexist together, apps can be migrated on an as-needed basis.
Hilt in action
Just to show you how easy to use Hilt is, let’s perform some quick DI in a typical Android app. Let’s make Hilt inject an AnalyticsAdapter into our MainActivity .
First, enable Hilt in your app by annotating your application class with the @HiltAndroidApp to trigger Hilt’s code generation:
Second, tell Hilt how to provide instances of AnalyticsAdapter by annotating its constructor with @Inject :
And third, to inject an instance of AnalyticsAdapter into MainActivity , enable Hilt in the activity with the @AndroidEntryPoint annotation and perform field injection using the @Inject annotation:
For more information, you can easily check out what the new annotations do in the cheat sheet section below.
Comes with Jetpack support!
You can use your favourite Jetpack libraries with Hilt out of the box. We provide direct injection support for ViewModel, WorkManager, Navigation, and Compose so far.
For example, to inject a Architecture Components ViewModel LoginViewModel into a LoginActivity : annotate LoginViewModel with @HiltViewModel , annotate the constructor with @Inject , and use it in an @AndroidEntryPoint activity or fragment as you’d expect:
Learn more about Jetpack support in the docs.
Start using Hilt
If you’re intrigued by Hilt and want to learn more about it, here’s some resources for you to learn in the way you prefer:
Getting started with Hilt
Learn how to add Hilt in your Android app with this guide.
Documentation
If you’re new to DI or Dagger, check out our guide to add Hilt to an Android app. Alternatively, if you already know Dagger, we’re also providing documentation on dagger.dev.
If you’re just curious about the new annotations and what you can do with Hilt, check out this cheat sheet in the section below.
For Dagger users
If you’re already using Dagger or dagger.android in your app, check out this migration guide or the codelab mentioned below to help you switch to Hilt. As Dagger and Hilt can coexist together, you can migrate your app incrementally.
Codelabs
To learn Hilt in a step-by-step approach, we just released two codelabs:
Sample code
Do you want to see how Hilt is used in existing apps? Go check its usage in the Google I/O 2020 app and in the dev-hilt branch of the Android architecture-samples Github repository.
Cheat sheet
This cheat sheet allows you to quickly see what the different Hilt and Dagger annotations do and how to use them.
Источник
Android Dependency Injection With Koin
March 29, 2021
Dependency injection is a programming technique that makes a class independent of its dependencies. This is made possible by decoupling the usage of an object from its creation. Many Android developers are familiar with Java-based dependency injection frameworks such as Dagger and Guice.
However, some frameworks are written completely in Kotlin for Kotlin. These frameworks include Koin and Kodein. This article goes through how to manage dependencies in Android using the new dependency injection framework — Koin.
Prerequisites
To follow through with this tutorial, you will need to:
- Have Android Studio installed.
- Have a basic knowledge of building Android applications.
- Have a basic understanding of Kotlin programming language.
Let’s get started!
What exactly is dependency injection
Being a software developer, you must, or might have heard about dependency injection but didn’t really understand what it is. You might even be asking yourself, why should I use this technique?
How important is it? Have I ever used it? Well, the answer to the last question is pretty simple. You have but without any dependency injections framework.
Consider the following scenario. You have two classes, A and B. Class B requires an instance of A for it to perform a specific task. It is correct to say that class B directly depends on class A.
Therefore, we often find ourselves creating an instance of the dependent class before using it or pass it as a parameter. All these are forms of dependency injection. This is fine for a small project.
However, as the project scales, maintenance and testing become challenging. This is where dependency injection frameworks come into play.
A dependency injection framework helps us to create and manage dependencies. As mentioned earlier, there are many Java-based Android dependency injection frameworks. However, with the increased adoption of Kotlin on Android, the demand for libraries written completely in Kotlin for Kotlin is rising.
Koin is a dependency injection framework that conforms to this need. It is a lightweight framework, easy to learn, and does not have much boilerplate code. Let’s see how we can use this framework to manage dependencies in our Android applications.
Getting started with Koin
Koin is fairly simple. All we need to do is create our classes, tell Koin how to create the dependencies, then we can call them whenever/wherever we need them.
Before we move any further, create an empty activity project and give it a name of your choice. Wait for the project build to complete then add the following dependency on your app-level build.gradle file.
Let’s go ahead and create some classes.
Creating project components
We are going to need some components that depend on each other for demonstration. Let’s create a scenario. Create a Kotlin file and in it add the following code.
The first class is a Student class, a student has a course of study and a friend to play with. Therefore, the Student class depends on those classes.
It needs them to call or access the study() and play() functions contained in the Course and Friend classes respectively. To solve this dependency we add the two classes as parameters.
This means that the Student class can not be instantiated without instances of Course and Friend classes.
Open the MainActivity file and replace the onCreate function with the following code.
The application uses View binding to access the default TextView with an id of text_view . Visit this link to learn more about View binding.
The code creates instances of all the classes.
Upon running the application, the text view will display:
There is nothing wrong with the application as it is. But, as we mentioned earlier, depending on this kind of dependency injection will make the application hard to maintain as it scales. Let’s see how Koin can help us manage these dependencies.
Creating a Koin module
Koin uses modules to create dependencies. Create a new Kotlin file with the name ‘module’ and add the following code.
The module function as the name suggests is used to create a module. single is used to create a singleton instance. This means that Koin will return the same instance of the class when the dependency is needed.
We have made Course a singleton since we assume that all the students do the same course. factory , on the other hand, is used when we want a new instance of the class every time we call it.
We have used the factory for both Friend and Student classes since we want a new instance whenever we call them. The get function is used to get the required dependency only if it has been specified in the module.
It detects the type of dependency we need and fetches it for us. That’s all we need for the module. Let’s go ahead and start Koin.
Starting Koin
Starting Koin is fairly simple. Create an application class with the name of your choice and add the following code to start Koin.
We use the startKoin function to start Koin.
And that’s it! Koin is fully set up. Now, let’s use Koin in our MainActivity .
Replace the onCreate method of the MainActivity with this.
The reduction of lines of code is noticeable. by inject delegate is used to lazily inject dependencies. We can also use the get function to get the dependency non-lazily .
Run the application again.
The code works fine, but, this time we have employed a dependency injection framework that helps a lot in ensuring our project is maintainable and can be easily tested.
Conclusion
In this article, we have gone through dependency injection and how to manage dependencies using a Kotlin dependency injection known as Koin. We have seen how Koin is easy to set up and work with.
We have also seen how dependency injection helps us in making our applications maintainable. I hope this tutorial gives you the basics you need to start using this great and lightweight framework.
Peer Review Contributions by: Wanja Mike
About the author
Peter Kayere is an undergraduate student at Jomo Kenyatta University of Agriculture and Technology studying Computer Technology. Peter has a great passion in software development particularly mobile web and android application development. Peter’s most used programming languages are Kotlin and Javascript.
Want to learn more about the EngEd Program?
Discover Section’s community-generated pool of resources from the next generation of engineers.
Источник
Dagger 2 для начинающих Android разработчиков. Внедрение зависимостей. Часть 1
Данная статья является второй частью серии статей, предназначенных, по словам автора, для тех, кто не может разобраться с внедрением зависимостей и фреймворком Dagger 2, либо только собирается это сделать. Оригинал написан 25 ноября 2017 года. Изображения и GIF — из оригинала. Перевод вольный.
Это вторая статья цикла «Dagger 2 для начинающих Android разработчиков.». Если вы не читали первую, то вам сюда.
Серия статей
Ранее в цикле статей
В последней статье мы обсуждали зависимости. Мы узнали, что такое зависимость, обсудили их типы, влияние на процесс разработки и поддерживаемость проекта.
Что такое внедрение зависимостей (dependency injection, DI)
Ранее мы поняли, что такое зависимость и как она влияет на проект. Сейчас разберем что такое внедрение зависимостей.
Перед тем, как разбирать внедрение зависимостей, нам нужно понять как избежать ловушки, в которой мы будем окружены зависимостями. Проблема сильных связей (hard dependency) как Белые Ходоки (White Walkers). Мы не должны присоединиться к их армии, напротив, нужно найти путь, чтобы победить их.
Стратегия решения проблемы сильных связей (hard dependency) или проблемы Белых Ходоков
Нам нужен четкий план для решения или предотвращения проблемы сильных связей. Эта стратегия или план называется внедрение зависимостей (dependency injection, DI). Другими словами, чтобы убить Белого Ходока вам нужно сжечь его или использовать оружие из драконьего стекла. Аналогично, чтобы избежать сильных связей, необходимо использовать внедрение зависимостей.
Внедрение зависимостей — это лишь один из методов предотвращения сильных связей. Существует много других способов. Для Android разработки этот метод считается наиболее простым и многие крупномасштабные проекты используют стратегию внедрения зависимостей.
Метод внедрения зависимостей
Внедрение зависимостей — это метод, при котором один объект предоставляет зависимости другого объекта. Зависимость (dependency) — это объект, который мы можем использовать (сервис). Внедрение (инъекция, injection) — это передача зависимости зависимому объекту (клиенту), который будет данной зависимостью пользоваться. Сервис — это часть состояния клиента. Передать сервис клиенту, вместо того, чтобы позволить клиенту создать или найти сервис — базовое требование шаблона проектирования «Внедрение зависимости» (DI).
Сравним это с Игрой Престолов. Серсея готовится к большой войне. Вместо того, чтобы сжигать все деньги в своем королевстве она пытается получить кредит у железного банка Браавоса. В этой ситуации деньги — это зависимость. Деньги нужны всем домам, чтобы вести войну. Таким образом внешний объект (железный банк) будет внедрять зависимость (деньги) зависимым объектам (домам).
Другими словами, внедрение зависимостей основывается на концепции инверсии контроля, которая говорит о том, что класс должен получать свои зависимости извне. Говоря просто, ни один класс не должен создавать экземпляр другого класса, а должен получать все экземпляры из класса конфигурации.
Пример 1
Хватить говорить. Давайте разбирать код. Рассмотрим небольшой пример с двумя сценариями. В первом сценарии создадим несколько классов с сильными связями (hard dependencies), то есть без использования внедрения зависимостей. Затем, следуя шаблону «Внедрение зависимости», мы избавимся от сильных связей.
Сценарий 1. Без использования внедрения зависимостей
Проблема: Битва бастардов — Старки (Starks) и Болтоны (Boltons) готовятся к войне, чтобы захватить Север. Нужно их подготовить и вывести на войну.
Поскольку пример может включать много домов, создадим общий интерфейс House , включим в него методы prepareForWar() и reportForWar() .
Далее создадим классы для домов Starks и Boltons . Классы будут реализовать интерфейс House .
Заметка: this.getClass().getSimpleName() просто возвращает имя класса
Далее нужно привести оба дома к войне. Создадим класс War и попросим оба дома подготовиться к войне и сообщить о ней.
Анализируем War
Рассмотрим конструктор класса War . Для работы ему необходимы два класса Starks и Boltons . Эти классы создаются внутри конструктора, готовятся к войне и сообщают о ней.
В хорошо спроектированном объектно-ориентированном приложении у каждого объекта минимальное количество обязанностей, объекты опираются на другие для выполнения большей части работы. В данном примере класс War зависит от Starks и Boltons . Это зависимости класса War . Без них War работать не будет. Перед тем, как класс начнет выполнять реальные функции, все его зависимости должны быть удовлетворены каким-либо образом. Зависимости класса War в этом примере удовлетворяются путем создания экземпляров классов в конструкторе.
Хотя вариант с созданием зависимостей внутри конструктора класса достаточно хорошо работает в небольших приложениях — он привносит недостатки по мере роста проекта.
Во-первых, класс становится довольно негибким. Если приложение должно работать на нескольких платформах или в нескольких режимах, например, необходимо заменить класс Boltons на другой или разделить его на несколько объектов. Сделать это становится не так просто.
Во-вторых, невозможно изолированно протестировать эти классы. Создание экземпляра War автоматически создает два других объекта, которые, в конечном итоге, будут тестироваться вместе с классом War . Это может стать проблемой, если один из объектов зависит от дорогого внешнего ресурса, например, Allies (союзники) или один из объектов сам зависит от множества других.
Как упоминалось ранее — борьба с сильными связями (hard dependencies) похожа на борьбу с Белыми Ходоками без надлежащего оружия.
Резюме
В этой статье мы рассмотрели зависимости и внедрение зависимостей в деталях. Ни один класс не должен создавать экземпляр другого класса, а должен получать все экземпляры из класса конфигурации.
Внедрение зависимостей — это метод решения или предотвращения проблемы сильных связей. Предоставляя зависимости извне, этот метод делает класс независимым, тестируемым и поддерживаемым.
Также мы рассмотрели пример с сильными связями (hard dependencies), создавая сценарий битвы бастардов.
Источник