Разработка сайта для Вашего бизнеса. Веб дизайн. Дизайн логотипа, фирменного стиля, рекламная фотография . Комплексный рекламный креатив.

Ralex. We do the work.
На рынке с 1999го года. Средняя ценовая категория. Ориентация на эффективность решений.
Ознакомтесь с нашим портфолио
Узнайте больше о услугах
Свяжитесь с нами:
E-mail: [email protected]
Tel: (044) 587 - 84 - 78
Custom web design & дизайн и разработка сайта "под ключ"
Креативный, эффективный дизайн. Система управления сайтом (СУС).
Custom flexible разработка систем электронной коммерции
Система e-commerce разрабатывается под индивидуальные потребности. Гибкая функциональность.
Search Engine Optimzation & оптимизация под поисковые системы (SEO)
Постоянная оптимизация и мониторинг сайта в поисковых системах. Достигаем результата быстро и эффективно
Custom logo design & дизайн логотипа и фирменного стиля
Многолетний опыт. Огромное портфолио. Уникальное предложение и цена.
профессиональная рекламная фотография
креативно, смело, качественно
Custom logo design & рекламный креатив. дизайн рекламы
Многолетний опыт. Огромное портфолио. Уникальное предложение и цена.

Dagger 2. Лікуємо залежності за методикою Google

  1. Dependency Injection Що, навіщо і коли це потрібно
  2. Створення класів породжує ...
  3. Можливість створювати об'єкти ...
  4. І ... залежно
  5. Dagger and JSR-330 Standart
  6. Трохи ще НЕ історії
  7. Інверсія управління ( англ. Inversion of Control, IoC)
  8. Reflection vs Compile time
  9. JSR-330
  10. Отже, прийшов час додати в наш код трохи магії ...
  11. Зверніть увагу на конструктор за замовчуванням
  12. Конструктор з параметрами - гарне місце для модифікацій
  13. І все ж - як це змусити працювати?
  14. Структура інжекції Dagger2.0
  15. Компоненти і Модулі
  16. Модуль - колекція генераторів
  17. Що таке Синглетон (англ. Singleton)?
  18. @Component
  19. Ініціалізація компонента generated code used
  20. Inject This! :)
  21. Puttin 'magic will work only after injection ... :)
  22. Custom Scopes і ефективне управління пам'яттю
  23. Життєвий цикл об'єктів
  24. І ще раз та сама матрьошка Компонент має область життя (scope)
  25. This mysterious 'plus' ...
  26. оголошення субкомпоненту
  27. Але ж там був модуль!
  28. Додавання субкомпоненту до кореня дерева залежностей
  29. анотація @Scope
  30. @ActivityScope
  31. @UserScope
  32. Наостанок ... .Що Інжект?
  33. Home readings
  34. сенс коду

Dependency Injection

Що, навіщо і коли це потрібно

Наша взаимовыгодная связь https://banwar.org/

Сьогодні ми поговоримо про інструмент, який допомагає поліпшити якість розробки для Android. Вирішити це завдання можна за допомогою Dependency Injection (DI). Зазвичай цей термін асоціюється з ін'єкціями, шприцами та трошки з «залежностями». Насправді, Dependency Injection - патерн проектування, що забезпечує реалізацію принципу інверсії залежностей і реалізує правила створення об'єктів і незалежність реалізацій.

Отже, у нас є клас, у класу є конструктор, і є кілька членів класу. Коли ви створюєте сутність цього класу, вам необхідно забезпечити клас інстанси тих самих типів, які оголошені для його членів класу. В даному випадку, це ім'я машини і тип двигуна Engine. Ви будете використовувати посилання на об'єкти, відповідно, посилання всередині вашого класу не будуть пустувати.

Таким чином, ви реалізуєте ОOП і можете створювати об'єкти.

Створення класів породжує ...

Створення класів породжує

  • Композиція - НЕ успадкування.
  • Посилання не будуть пустувати.

Можливість створювати об'єкти ...

Ви можете створити об'єкт, задати ім'я машини і створити якийсь новий двигун.

Доступно створення різних об'єктів, наприклад, створення двигуна іншого типу або просто іншого двигуна.

Припустимо, ви можете створити два різних об'єкта, які будете використовувати. В даному випадку, той самий двигун від «Патріота». Відповідно, якщо ви поставите цей двигун в Jeep Grand Cheerokee - це буде трохи дивно. Але, тим не менш, ви можете це зробити. При цьому використовується так званий патерн «композиція», коли сутності, які ви створюєте, будуть включатися в іншу сутність, і це буде, як ви бачите, не успадкування, а саме композиція.

Тут все дуже просто: якщо ви подивіться на SuperTunedEngine, зрозумієте, що насправді він є спадкоємцем певного типу, який вже оголошений заздалегідь, а також, можливо, є реалізацією інтерфейсу - для нас це не принципово. В даному випадку Engine може бути інтерфейсом.

Дивлячись на два оголошення, ви бачите: ми можемо зробити так, що два об'єкти будуть залежати від будь-якого іншого об'єкта. Власне, це і є залежність. Таким чином, можливість створювати об'єкти породжує залежності - досить банальна річ.

І ... залежно

Car depends on Engine. Engines may vary. We'll probably need different engines for testing and production.

Як ви бачите на схемі (зображення не з нашого прикладу), залежно бувають дуже різні. У вас будуть залежні сервіси, залежні activity, презентери, в'ю, контролери. Всі ці сутності переплетені між собою залежностями. Якщо спробувати виразити це графічно, вийде приблизно те, що ви бачите зараз на картинці.

У реальній робочій системі залежностей буде набагато більше. Тести, які проводять відомі компанії, що надають інструментарій для тестування Android-додатків, показують, що залежностей, навіть в простих, на перший погляд, додатках, бувають тисячі. В середньому тисячі і десятки тисяч залежностей зустрічаються навіть в найпростіших додатках. Щоб реалізовувати ці залежності якомога більше ефективно, не інстанціруя кожен раз всередині свого класу якісь інші класи і не дописуючи купу коду, який буде повторюватися і додавати вам зайву роботу, існує інструмент Dagger.

Dagger and JSR-330 Standart

анотація @Inject

Dagger заснований на стандарті JSR-330. Цей стандарт Google використовує дуже давно, і це - стандарт для Java Injection.

Трохи ще НЕ історії

  • Dagger 2 - Google, Greg Kick
  • Dagger - Square, Jake Wharthon
  • Guice - Google, Jesse Wilson

Заглянемо трохи в історію: Google колись створив такий продукт як Guice (в народі його називають «Джус», а в наших широтах - «Гусак»). Guice працював з рефлексією, він слідував анотацій, але згодом розробники з Square вдосконалили систему, яка була в Guice і створили Dagger1.

Dagger1 був крутим інструментом, але, як показує практика, і тут можна щось поліпшити. До речі, Dagger1 теж використовував рефлексію. І в 2015 р розробники з Google випустили Dagger2. Здається, що ще зовсім недавно Jake Wharton (відомий розробник з компанії Square) анонсував його випуск з прицілом на осінь - обіцянка виконана, у нас є якісний і випереджаюче конкурентів за результатами тестів продукт.

Інверсія управління ( англ. Inversion of Control, IoC)

Inversion of Control, IoC)

Повернемося до стандартів і термінології. Отже, у нас є продукт, який з'явився в ході еволюції. Він використовує JSR-330, який, надає цілий ряд анотацій. Крім того, він слідує певним принципам, свого роду паттернам розробки, один з яких - Inversion of control (IoC).

Процес надання зовнішньої залежності програмного компоненту є своєрідною формою «інверсії контролю» (англ. Inversion of control, IoC), коли вона застосовується до управління залежностями. Відповідно до принципу single responsibility об'єкт віддає піклуватися про побудову необхідних йому залежностей зовнішньому, спеціально призначеному для цього спільного механізму.

Ця річ пов'язана з архітектурними паттернами. Ми повинні писати додаток таким чином, щоб внутрішні класи, пов'язані з доменної логікою, не залежали від зовнішніх класів, щоб додаток було написано грунтуючись на інтерфейсах. Таким чином реалізується розмежування зони відповідальності. Звертаючись до якоїсь реалізації, ми звертаємося, в першу чергу, до інтерфейсу. Inversion of Control реалізується через Dependency Injection власне сам інструментарій називається Dependency Injection (DI).

Reflection vs Compile time

Dagger2 використовує кодогенерацію, на відміну від Dagger1, який використовував рефлексію.

JSR-330

JSR-330 aka javax.inject

  • @Inject, @Qualifier, @Scope. etc.
  • Standardized Dependency Injection API
  • Reference Implementation: Google Guice 2.0
  • Also supported by Spring since 3.0
  • Defines API, not injector implementation or configuration

JSR описує не тільки анотацію @Inject, а й надає цілий пакет анотацій, які дозволять вам декларувати яким чином будуть взаємодіяти суті для забезпечення Dependency Injection.

Наприклад, я розповідаю про певної міри Dependency Injection-продуктів, які дотримуються цього стандарту. Є інші продукти, які цього стандарту не дотримуються, про них ми сьогодні говорити не будемо, але вони існують. Є @Inject, @Qualifier, @Scope - про них ми поговоримо пізніше. Ці анотації були створені тільки для Dagger2, вони існують і для інших інжекторів, наприклад, Guice.

Отже, прийшов час додати в наш код трохи магії ...

Отже, прийшов час додати в наш код трохи магії

Ми почнемо з того, що аннотіруем члени класу анотацією @inject. Все досить просто. Щоб інстанціювати надалі ці залежності і наш інструментарій Dependency Injection зміг правильно підібрати куди саме інстанціювати і що, ми повинні також анотувати конструктор. Тут ситуація стає трохи цікавіше.

Зверніть увагу на конструктор за замовчуванням

Зверніть увагу на конструктор за замовчуванням

Найпростіший спосіб забезпечити инжекцию - створити конструктор за замовчуванням. Потім анотувати Інжект сам конструктор за замовчуванням і ті члени, які вимагають інстанцірованія цього класу. Це робиться дуже просто.

Конструктор з параметрами - гарне місце для модифікацій

Конструктор з параметрами - гарне місце для модифікацій

У реальному житті нам знадобляться конструктори з параметрами. Деякі з них система зможе підібрати автоматично, якщо у них є конструктори за умовчанням. А деякі, наприклад, той же Engine, можливо доведеться конструювати вручну.

Також ви будете инжектировать презентери за допомогою таких конструкторів, це дуже часто використовується в MVP (Model-View-Presenter).

І все ж - як це змусити працювати?

І все ж - як це змусити працювати

Структура інжекції Dagger2.0

Структура інжекції - взаємозв'язок компонентів Dagger, які дозволяють нам об'єднати анотації @inject і об'єднати оголошення класів.

Компоненти і Модулі

Pic
Pic. author - Miroslaw Stanek from Azimo
http://frogermcs.github.io/dagger-graph-creation-performance/

Структура інжекції Dagger включає в себе компоненти і модулі. Якщо ви подивіться на картинку (зі статті Мирослава Станек з компанії Azima), побачите, що компоненти - контейнери для модулів, причому всередині одного компонента можуть бути інші. Пізніше ми побачимо, що компоненти, які вкладені, називаються субкомпоненти (@ SubСomponent). І називати їх просто «компоненти» ми не можемо за правилами інжекції.

Модуль - колекція генераторів

Модуль - колекція генераторів

Анотація @Module - анотація, яка говорить, що ось ця сутність - ось цей клас - є модулем, який буде генерувати інстанси об'єктів.

Тут теж все досить просто. Анотації, які генерують, - це анотація provides. Анотація provides просто вказує, що даний метод модуля буде поставляти вам сутність. Найцікавіше буде відбуватися всередині цього методу.

Вам необхідно буде, слідуючи цим правилам, якимось чином інстанціювати об'єкт. Деякі об'єкти будуть залежати один від одного. Деякі об'єкти будуть залежати від членів класу модуль, які ви можете зберігати в модулі. Наприклад, той же контекст, ви можете покласти в модуль. Модуль про нього пам'ятає і потім, при інстанцірованія тих же самих прензентеров, ви будете генерувати нові сутності презентерів на основі контексту, який модуль запам'ятав один раз при його створенні.

Як ви бачите, у модуля є конструктор. В даному випадку замість контексту ми передаємо Application. При створенні чогось нового можемо повертати те, що зберігається в самому модулі.

Що таке Синглетон (англ. Singleton)?

При створенні деяких сутностей, ми задаємо певні параметри. Сінглтон (англ. Singleton) - інструкція, яка говорить, що там, де інжектор буде знаходити анотацію @inject, він не повинен інстанціювати новий об'єкт, а повинен перевикористати вже істанцірованний вже один раз об'єкт-Синглетон.

@Component

Компонент - хост для модулів, інжектор для класів, корінь дерева залежностей.

З компонентом все трохи цікавіше. Компонент повинен враховувати час життя модулів, які він включає. Якщо ми спробуємо використовувати Сінглтон для компонента, який використовує час життя інстанцірованія, виникнуть конфлікти. Тому потрібно чітко розуміти, що, наприклад, компонент для Application, буде Синглетон, тому що об'єкт класу Application існує в єдиному екземплярі, і існують весь час життя додатки. Для activity, наприклад, це теж може бути Синглетон, і його час життя буде прив'язане до часу життя activity. При необхідності існує можливість анотувати компонент додаткової анотацією @Singleton. Є список модулів, який включає в себе це компонент.

Наприклад, в Activity буде анотація inject. У компоненті повинні бути вказані модулі, які роблять provides цієї activity. Ви повинні обов'язково вказати в компоненті, куди ми інжектіруем. Т. е. Ми повинні вказати конкретний клас, причому, зверніть увагу, що тут не можна, наприклад, написати BaseActivity як базовий клас, тому що тоді інжекція відбудеться тільки в Base aActivity, а в MainActivity, куди потрібно, наприклад, проінжектіть якийсь презентер, правила будуть трохи іншими.

Ми повинні вказати конкретний клас, причому, зверніть увагу, що тут не можна, наприклад, написати BaseActivity як базовий клас, тому що тоді інжекція відбудеться тільки в Base aActivity, а в MainActivity, куди потрібно, наприклад, проінжектіть якийсь презентер, правила будуть трохи іншими

Метод inject - опис того, хто залежить. Модулі - опис тих, хто надає залежності.

Давайте повернемося до модуля. Модуль оголошується як клас. Важливо зауважити, що модуль - реальний клас, який має справжні посилання на реальні об'єкти. І він створюється вами вручну при оголошенні компонента, при зв'язці. Компонент, в свою чергу, - об'єкт, який генерує Dagger. Якраз в цей момент відбувається магія кодогенераціі. Тому компонент оголошується як інтерфейс.

Ініціалізація компонента generated code used

Ініціалізація компонента generated code used

Ось, наприклад, DaggerAppComponent инициализируется всередині нашого застосування. Зверніть увагу, generated code used (ініціалізація компонента) означає, що ми використовуємо генерований код. Наприклад, можна виявити DaggerAppComponent. Як ви бачили раніше, ніякого префікса Dagger не було. Звідки ж він з'явився? Так, Dagger згенерував код. Він його генерує досить швидко. Якщо ви випадково поламаєте инжекцию, про яку ми зараз говоримо (про її структурі), в результаті у вас DaggerAppComponent не з'явиться. Якщо ви допустили невелику помилку і неправильно вказали клас, генерація не спрацює - DaggerAppComponent не з'явиться, і вся магія, яка забезпечує нам прив'язку наших activity і інших класів, не запрацює без згенерованого класу. Тому що компонент є коренем усього дерева - це основа. І без нього все інше не працює. Слід уважно ставитися до того, як ми будуємо инжекцию до цього, і правильно використовувати компонент.

Також слід зазначити, що у компонента є builder. Builder - патерн проектування. Ми розуміємо, що у білдера є якісь аргументи, які визначають, як буде будуватися далі наш компонент, наприклад, метод AppModule - автоматично згенерований метод, який приймає в якості аргументу інстанси-класом AppModule. Модуль ми створюємо руками і задаємо для нього параметри. І викликаємо метод build для отримання AppComponent. В цьому посиланню є приклад з реального коду: http://github.com/c-mars/Dagger2Scopes.git .

Inject This! :)

:)

Puttin 'magic will work only after injection ... :)

У класу Application є методи, які надають доступ до нього. Тим більше, це не статичний метод, ви можете просто отримати з get application контекст. Можете його прікастіть до свого класу - вийде те ж саме і ніякої магії тут не буде. Але, що для дійсно важливо, у нас буде цей getAppComponent.

Ідея в тому, що Application зберігає AppComponent. Ми викликаємо якісь додаткові методи на цьому компоненті, і потім застосовуємо метод inject. Як ви помітили, цей той інжект із зазначенням конкретного класу, який ми оголосили в компоненті. В даному випадку це - клас LoginActivity. Ви бачите в анотації інжект, бачите, як ми заінжектілі залежності. Магія запрацює тільки після інжекшена.

Custom Scopes і ефективне управління пам'яттю

Custom Scopes, як такі, служать для того, щоб забезпечити вашим істанцірованним класах певний час життя.

Життєвий цикл об'єктів

Pic
Pic. author - Miroslaw Stanek from Azimo
http://frogermcs.github.io/dagger-graph-creation-performance

Наприклад, у вас є activity, і вони живуть досить недовго, з одного на екрану на інший переходите і все вбиваєте. Тобто все, що заінжекшено в activity, цілком можна після цього почистити, і додаток буде споживати менше пам'яті. Якийсь клас призначених для користувача даних, наприклад, User, буде жити між логінами. Application Scope - найголовніший, кореневої scope, що живе найдовше.

І ще раз та сама матрьошка
Компонент має область життя (scope)

Pic
Pic. author - Miroslaw Stanek from Azimo
http://frogermcs.github.io/dagger-graph-creation-performance/

This mysterious 'plus' ...

This mysterious 'plus'

Тепер звернемо увагу на плюс.

оголошення субкомпоненту

оголошення субкомпоненту

Анотація @Scope дозволяє вам генерувати Скоуп певного часу життя. Наприклад, ActivityScope буде жити стільки, скільки живе activity. Їм анотує компоненти як субкомпоненти.

Але ж там був модуль!

Але ж там був модуль

Дані всередині описуються також, як в кореневому компоненті. За винятком однієї речі: коли ви викличете плюс, передасте туди модуль і інстанціруете його, ви отримаєте подкомпонент, який вам потрібен.

Додавання субкомпоненту до кореня дерева залежностей

Додавання субкомпоненту до кореня дерева залежностей

Для чого це використовується? Щоб Скоуп, які можна оголошувати як інтерфейси, обмежували час життя наших об'єктів.

анотація @Scope

анотація @Scope

Цей вид @Scope буде обмежувати час життя статично, в залежності від того, куди ви заінжектілісь. А інший буде обмежувати динамічно.

Динамічний означає, що ви будете керувати ним вручну, і все буде віддалятися з допомогою garbage collector ( «збирач сміття»).

Ми аннотіруем компонент, необхідний Скоуп.

@ActivityScope

@ActivityScope

@UserScope, наприклад, як він буде працювати цей той самий Скоуп, який має @Retention (RUNTIME). Їм можна буде керувати вручну.

@UserScope

@UserScope

Щоб їм управляти вручну, ви зберігаєте посилання на компонент всередині програми поруч з AppComponent.

Щоб їм управляти вручну, ви зберігаєте посилання на компонент всередині програми поруч з AppComponent

Він створюється за допомогою особливого методу, приклад коду, який ви можете побачити. Потім код почистили, відправили його в реліз, і garbage collector його видалить. Коли це відбувається? Коли користувач вийшов із системи ( «вилогінілся»). Наступного разу, коли ви викличете ще один createUserComponent, цей компонент створиться ще раз з іншими даними користувача.

Наостанок ... .Що Інжект?

  • Модулі демо-даних.
  • Презентери.
  • Сінглтон.
  • Тестові реалізації класів.
  • ... Все інше, що інстанціруется і створює залежності.

Насправді, Інжект треба те, що допоможе ефективніше Інжект пам'ять і писати код. Презентери однозначно повинні використовуватися.

Синглетон - це зручно. У прикладі, який я зараз наведу, ми Інжект Mock-дані для демо-версії, і їх же можна було використовувати з варіаціями при тестуванні.

Home readings

Sample code: http://github.com/c-mars/Dagger2Scopes.git

Рекомендую почитати Fernando Cejas про патерни проектування. Мирослав Станек дуже добре описав Скоуп. У нього є чудова стаття про те, як правильно управляти @Retention (RUNTIME) і вчасно чистити пам'ять. І, звичайно, відвідайте офіційну сторінку Dagger2.

сенс коду

Як ми організували швидку Agile-розробку з використанням Mock-модулів і в підсумку обігнали сервер-сайд.

Історія така. Dagger 2 ми використовували в проекті з юніт-тестами, c правильним поділом MVP, але ключовим моментом було, що сервер-сайда на той момент не було. А ми писали додаток, яке повинно з сервера забрати дані, показати, все це красиво обробити, проаналізувавши дані. Основне завдання стояла, щоб при появі REST сервісів ми змогли швидко на них перейти. Швидко це зробити, можна тільки змінюючи код вручну. При наявності модулів і компонентів, після появи сервера, ми легко замінили Mock-дані (які поставлялися за допомогою інжекції) на реальні дані з REST API, замінивши тільки один модуль і один рядок коду в оголошенні кореневого компонента.

Що Інжект?
І все ж - як це змусити працювати?
Що таке Синглетон (англ. Singleton)?
Звідки ж він з'явився?
Коли це відбувається?
Що Інжект?
Категории
  • Биология
  • Математика
  • Краеведению
  • Лечебная
  • Наука
  • Физике
  • Природоведение
  • Информатика
  • Новости

  • Новости
    https://banwar.org/
    Наша взаимовыгодная связь https://banwar.org/. Запустив новый сайт, "Пари Матч" обещает своим клиентам незабываемый опыт и возможность выиграть крупные суммы.


    Наши клиенты
    Клиенты

    Быстрая связь

    Тел.: (044) 587-84-78
    E-mail: [email protected]

    Имя:
    E-mail:
    Телефон:
    Вопрос\Комментарий: