Все о кинжалах | Fresher
Один из верных способов убить или ранить противника — нанести ему колющий удар. Кинжал является простейшим колющим оружием. Он имеет короткий клинок и удерживается одной рукой. В первую очередь служит для нанесения колющих ударов, но многими из кинжалов можно резать как хозяйственным ножом. Один из основных типов оружия, кинжал известен во всех частях света и используется с эпохи каменного века. Для нанесения колющего удара кинжалы обычно имеют суживающийся клинок, часто обоюдоострый. Разнообразие очертаний клинка очень велико. Некоторые стали традиционными для определенных районов, другие диктуются материалом изготовления. Здесь показаны лишь главные типы. 1. Широкий треугольный клинок, такая форма компенсировала мягкость металла. 2. Узкий треугольный клинок, идеальный для кинжала. 3. Асимметричный малайский крис. Клинок не всегда волнистый. 4. Тяжелый листовидный клинок. 5. Изогнутая арабская джамбия. 6. Дважды изогнутый клинок. Распространен в Индии и Персии. 7. Клинок в форме боуи. Спинка срезана, чтобы конец можно было сделать обоюдоострым. Разнообразные формы сечения показывают, как человек пытался получить возможно более жесткий клинок при его возможно меньшей толщине.Кинжалы
Зачем нужен короткий клинок, когда очевидно, что длинный имеет больше шансов первым достичь противника? Не зря же воины издревле вооружались длинным оружием. Тем не менее, маленькие размеры кинжалов бывали очень даже полезны, потому они и существовали наряду с такими большими и грозными старшими братьями, как мечи.
Но когда противник приблизился уже слишком близко, то тут длинным клинком не сильно-то помашешь. Или в небольшом помещении, где негде даже замахнуться. А при неожиданной атаке может совсем не хватить времени на то, чтобы вытянуть внушительный меч и встретить, как подобает, противника. В таких вот ситуациях короткий клинок, которым меньший брат, кинжал, отличается от своего старшего брата, меча, и имеет преимущества, как в скорости реакции, так и в маневренности. А небольшие размеры позволяют легко его спрятать от чужого взора, что дает уже преимущество неожиданности атаки с близкого расстояния. И наконец, удобство, когда нет возможности иметь при себе громоздкое и мешающее оружие, то клинок небольших размеров все равно лучше, чем ничего.
Итак, хотя кинжал и не является основным оружием воина, но значение его, как вспомогательного, от этого не меньше.
Так что же такое кинжал? Как уже выше было сказано – меньший брат меча. И это, пожалуй, будет самое точное определение, потому, что все существующие ему описания, весьма неточны и не проводят однозначную границу между понятиями «нож», «кинжал», «кортик». Судите сами:
- Нож – холодное оружие или инструмент с асимметричной заточкой.
- Кинжал – холодное оружие, как правило, с двумя лезвиями, короткой или средней длины (до 50 см).
- Кортик – холодное оружие, как правило, с ромбического сечения двухлезвийным клинком средней длины (до 40-50 см).
Поэтому, и использование термина «кинжал» носит скорее формальный характер и больше связан с устоявшимся обозначением, а не с сутью (подобно тому, как японскую катану называют мечом, а не саблей, каковой она есть).
Составные части кинжала
Классификация кинжалов
Если следовать духу знаменитого Эварта Оукшотта, английского исследователя холодного оружия, давшего ему приемлемую классификацию, то кинжалы можно разделить следующим образом.
По геометрии клинка
-
Прямой равномерно сужающийся к острию клинок (треугольный):
- Узкий (длина значительно преобладает над шириной в области пятки)
- Широкий.
-
Прямой клинок с равномерной шириной в нижней части (примыкающей к рукояти):
- С равномерным сужением к острию.
- С односторонним сужением к острию и оболонью или без нее (характерен для одно- и полуторасторонних лезвий).
- Стилет.
- Прямой копьевидный клинок.
-
Изогнутый клинок:
- С одним изгибом (саблевый тип).
- С двумя изгибами (ятаганный тип).
- Пламевидный клинок (фламберг).
Поскольку основное предназначение кинжала – колющий удар, очевидно, что идеальным клинком для этой цели будет тип IIc или Ia. Клинок типа Ib за счет большого поперечного сечения хуже справляется с уколом, но при такой форме он менее требовательный к твердости материала, который пошел не его изготовление. Остальные типы клинков являются компромиссом между способностями колоть и резать, а потому подходят именно для комбинированного колюще-режущего удара. Исключение становят клинки типа IVa и IVb, которые при значительном изгибе уже не могут применяться для нанесения уколов.
По типу сечения клинка
- Плоский.
- Линзовидный (выпуклый).
- Вогнутый.
- Ребристый.
- Трехгранный.
- Ромбовидный.
- Шилоподобный (стилет).
Сечение типа A самое гибкое и непрочное по отношению к поперечным усилиям. Именно целям усиления стойкости к таким воздействиям служат остальные типы, у которых грани способствуют сопротивлению на изгиб.
По типу крепления рукояти
- Безчерешковое крепление к пятке клинка.
- С черешком неполной длины.
- С черешком на всю длину рукояти.
Безчерешковый тип крепления рукояти применялся только в ранних кинжалах, поскольку надежность его оставляла желать лучшего. Самым надежным креплением есть последний вариант.
По типу рукояти
- Прямая рукоять без упоров сверху и снизу.
- Рукоять с упором в части примыкающей клинку.
-
Рукоять с навершием (головкой):
- С центрально расположенной головкой.
- С наклоненной в одну сторону головкой.
- С раздвоенной головкой.
-
Рукоять с двумя упорами (I-подобная).
- Односторонняя (половинчатая).
- Двусторонняя.
- Изогнутая рукоять (пистолетный тип).
Самым распространенным типом ранних рукоятей кинжала является тип 1 – примитивная прямая рукоять без упоров, позволяющая соскальзывать руке на лезвие и не обеспечивающая надежного хвата рукояти. Преобладающее число так называемых национальных ножей имеют простую рукоять. Предназначенные для профессионального использования более поздние кинжалы уже лишены этих недостатков, и они оснащались рукоятями с упорами.
По типу гарды
- Без гарды.
-
Простая крестовина (крестовая гарда):
- С прямыми краями.
- С опущенными или загнутыми в сторону клинка краями.
- С поднятыми или загнутыми в сторону рукояти краями.
- С асимметрично загнутыми краями.
- Крестовина с защитной дужкой.
-
Гарда-щиток.
- Полная.
- Половинная.
Ранние формы кинжалов чаще всего встречаются либо вовсе без гарды, либо с небольшой гардой типа 1а.
Применение кинжала
Использование кинжалов во время ведения боя было нехарактерным из-за их короткой досягаемости и небольшой мощи, бессильной против доспехов. Исключением служили рукопашные схватки в тесном строю, в характерной для Европы тактике и практически неприменяемой в странах Востока. Хотя существовали узкие клинки, специально предназначенные для проникновения между сочленениями защитных доспехов и подрезания их креплений. Позже, в пору начала порохового периода, когда произошел отказ от тяжелых и уже бесполезных лат и мощного оружия, пробивающего их, кинжал занимает место боевого щита и используется не только в качестве защиты, но и в качестве атакующего оружия левой руки.
Небольшие размеры позволяют использовать его как скрытое или замаскированное оружие, что сделало кинжал популярным среди наемных убийц. Кроме того, его можно метнуть, увеличив, таким образом, расстояние досягаемости. А дамам пришлись по душе стилеты с легким и прочным клинком, который можно было хорошо замаскировать под шпильку.
В то же время при надлежащем оформлении рукояти и ножен прикрепленный на поясе кинжал служил не только свидетельством общественного статуса своего хозяина, но и был достойным украшением костюма.
Характерно, что кинжал в европейских школах фехтования использовался как дополнительная защита и обман противника, но особо на нем внимание не акцентировалось. И только в XVIII веке появились попытки систематизации техники владения кинжалом, в том числе и с режущими ударами. В то же время на Востоке, и в частности Японии, мастерству владения малым клинком уделялось отдельное внимание.
Самый сильный удар, направленный по вертикали вниз, обеспечивал способ а) (см. рис.) удержания кинжала. Способ b) наиболее распространен, поскольку позволяет легко изменять направление удара. Специфические восточные ножи еще больше расширяют возможности и направления удара.
Традиционное место кинжала в ножнах на поясе слева спереди, чтобы удобно было достать правой рукой. Но вот среди арабов принято носить его по центру, а в Индонезии могут носить сзади за поясом. Шотландцы свой дирк носят, как положено, на поясе, а скин ду на правой голени за резинкой гетра. Еще одно излюбленное расположение кинжала – сзади с правой стороны ниже пояса. Но современные материалы крепления расширили список удобных мест: на левом плече или предплечье, горизонтально на поясе сзади или на правом бедре.
Классические европейские кинжалы
Квиллон
Немногие знают, что у средневекового меча была уменьшенная копия – квиллон, которая носилась на правом боку рыцаря и предназначалась для нанесения ударов между сочленениями доспехов противника. Кинжал мог располагаться и сзади, чтобы замаскировать свое присутствие. Тогда он наклонялся влево, если использовался при отсутствии щита, и вправо, если вместо меча.
Дага
В более поздний период квиллон трансформировался в узкую дагу. Предназначение у нее было все то же – левая рука фехтовальщика, но зато у этого кинжала появились крюки для захвата и ломки клинков и защитная дужка для руки на гарде. А некоторые экземпляры были снабжены механизмами для выпуска дополнительных клиньев.
Баллок, рондел, баселард и ушастый (бургундский) кинжал
Следующая группа средневековых кинжалов имела обычно узкий и массивный клинок стилетного типа и предназначалась для колющих ударов. Основная специализация их была в применении против доспехов. Главное различие и них было в оформлении рукояти и гарды.
Баллок имел характерную фаллическую форму рукояти. Форма сечения клинка, как правило, была треугольная, ромбическая или конусоподобная.
Позже его стали делать с узкими лезвиями, но острие все равно оставалось заметно утолщенным, с ромбическим сечением, для придания прочности.
Характерным для этого кинжала было наличие пикассо, незаточенной области лезвия возле пятки.
Рондел также получил свое название не за особенности клинка или пользования, а за форму рукояти. Также, как у предыдущий баллок, рондел выполнялся с разными клинками, в основном с двумя лезвиями или 4-гранными. Его отличие – дисковидные гарда и навершие. Довольно примитивная форма весьма эффективно выполняла свои задачи – не допускала соскальзывания руки ни в одну, ни в другую сторону, и обеспечивала защиту той же руке от клинка противника.
Баселард (от названия города Базель в Швейцарии) или швейцарский кинжал, как правило, имел 4-гранный клинок. Его обычно деревянная рукоять была I-подобная, с двумя парами противостоящих расширений, которые служили упором для руки. Нижнее расширение часто упрочнялось металлическими накладками и дополнительно выполняло функцию отсутствующей гарды.
Бургундский кинжал получил название «ушастый» благодаря двум дискам, которые образовывали навершие. Если вначале их размещали параллельно рукояти, то со временем их стала больше и больше отклонять в стороны. Крайняя форма – перпендикулярное положение относительно рукояти. Выполнялся без гарды. При ударе сверху вниз большой палец размещался между «ушами» и помогал руке не соскальзывать на лезвие. Характерная реализация клинка – одно лезвие делалось длиннее другого.
Мизерикордия и стилет
Мизерикордия, кинжал с узким клинком без заточенных граней, способный лишь на колющие удары. В ранние века он использовался для поражения рыцаря в доспехах сквозь щели в них. Позже стал применяться для добивания противника в избавление его от мук, за что и получил свое название, означающее «кинжал милосердия». В отличие от вышеописанных вариантов не имел конкретной формы рукояти, и мог иметь любую из них, тем самым подпадая под одно из предыдущих определений.
Поздняя форма кинжалов стилетного типа, собственно, стилет, считается развитием мизерикордии. У него тоже клинок в форме круглого или граненого штыка. Но для удобства пользования оснащен простой крестовидной гардой и небольшим навершием. Форма кинжала, идеальная для проникновения, а потому не требующая значительных физических усилий, снискала ему популярность у дам в качестве личного оружия защиты.
Чинкуэда
На фоне привычно узких европейских кинжалов резко выделяется популярный в XV-XVI веках в Италии и в соседней с ней Германии кинжал чинкуэда. У него очень широкая пята, и за ее размер он и получил свое название «пять пальцев». Лезвие при длине 35-40 см резко сужается к острию. Чтобы обеспечить необходимую твердость клинку у кинжала несколько ребер жесткости.
Рукоять с центрально расположенной головой, обычно выполнялась из дерева. Края крестовины были сильно наклонены в сторону клинка. Носили его обычно скрытно, сзади за поясом в горизонтальном положении.
Восточные кинжалы
Танто, кайкэн и другие
Отношение к оружию в Японии сакральное. Оно проявляется даже в такой незначительной, на наш взгляд, детали как, какой тип кинжала можно носить вместе с определенным мечом. Так танто или косигатана с клинком от 10-30 см можно носить и использовать только вместе с самурайским мечом катана или его коротким вариантом вакидзаси, и нельзя брать в комплект к длинному мечу тати. Вообще то, танто вместе с полноразмерным мечом катана и коротким викидзаси составляют по самурайским понятиям единое целое – полный набор самурайских мечей. Причем именно мечей, а посему и использование «короткого меча», как дословно переводится название «танто», должно быть исключительно в качестве оружия, например, добить поверженного врага или сделать церемониальное харакири. Для других, не боевых, целей существует иной кинжал – когатана ( у нас его часто ошибочно называют кодзука), который, кстати, можно использовать и по-боевому, для метания. Второй кинжал, который тоже входил в набор традиционной экипировки самурая, когай, напоминает стилет. Им самурай пользовался как вертелом для приготовления еды, как шпилькой для волос или даже как палочкой для письма. Имел он и боевое предназначение – мог втыкаться в голову мертвого врага, как «подпись автора», или ту же голову когаем пришпиливали к поясу как трофей. И когай, и когатана втыкались в ножны большого меча самурая.
Поскольку танто часть набора самурайских клинков, то и форма его должна быть общей с бо̀льшими элементами комплекта мечей. Тем не менее, бывают и небольшие отклонения, как то двусторонняя заточка лезвия. У танто, как и у среднего и большого меча, наличествует гарда (цуба). Традиции допускают отклонения для «короткого меча» и в форме гарды (цубы). Если она половинная, то форма кинжала называется хамидаси, а если вовсе отсутствует – то айкути.
Танто с толстым клинком и трехгранным его сечением, ёрои-доси («пробивающий броню»), использовался, как можно судить из названия, против воина в доспехах. Этот кинжал похож на длинный меч тати, а потому только с ним его и можно носить.
Самый маленький танто носит название кайкэн. Подобно тому, как средневековые европейские дамы использовали стилет, женщины из рода самураев и даймё (придворная знать) раньше носили его в поясе кимоно оби для самообороны или «последнего способа сохранения чести», самоубийства (дзигая). Мужчины в тех же целях (харакири, сэппуку) использовали ритуальные танто, кусунгобу.
В качестве скрытого оружия стилетного типа в Японии использовались традиционные палочки-заколки для причесок кансаси. Костяные, металлические или деревянные в 20 см длины с заточенным острием при правильном применении они могут нести серьезную опасность. Считается, что кансаси и поныне успешно используется ниндзя.
Катар (джамадхар)
Уникальный для своего времени (а первые упоминания датируются XIII веком) индийский тычковый кинжал катар или джамадхар впечатляет, прежде всего, своей конструкцией, а уже потом богатством форм исполнения. Катар использовался как вспомогательное оружие для левой руки. Характерным его элементом была Н-подобная рукоять-конструкция рамочного типа.
Клинок мог быть один или несколько, их размещение могло быть как на одной стороне, так и на разных, форма клинка могла быть как прямая, так и изогнутая, и даже типа фламберг, ширина клинка могла быть как большой, как у чинкуэды, так и очень узкой. Даже длина клинка могла достигать до метра, переводя это оружие уже в разряд мечей и главного оружия. Встречались и механические формы катара, которые подобно европейской даге при сжатии могли выбрасывать дополнительные клинки. Особо интересны экземпляры с уникальной заточкой лезвия отдельными выемками, что очень напоминает современную заточку-серрейтор.
Индийские оружейные мастера для изготовления катара использовали местный вариант булатной стали. При этом лезвие вместе с рукоятью ковалось из одного куска, что давало максимальную прочность соединения деталей. А в зависимости от статуса воина, катар украшался чеканкой, цветными эмалями и драгоценными металлами.
Пхур-Бу (пхурба, кила)
Этот кикжал многим знаком, скорее всего, благодаря кинофильму «Тень» 1994 года с Алеком Болдуином в образе борца со злом Человека-Тени. Тем не менее, это не художественный вымысел, а реальный ритуальный кинжал, который используется тибетскими буддистами в обрядах против злых духов. В свете того, что он не применяется как оружие, совершенно не имеет значение его трехгранное лезвие или рукоять, украшенная 3 лошадиными головами Хаягривы, тибетского гневного божества-защитника из индуистской мифологии.
Национальные кинжалы восточных народностей
Мужчины многих народностей Азии, до поглощения их современной цивилизацией, находились в условиях тяжелых для выживания, под постоянной угрозой нападения, как зверей, так и врагов. Они вынуждены были никогда не расставаться с оружием, в частности с кинжалом, как небольшим и необременительным предметом. Эта особенность уклада нашла свое отображение в национальном костюме, где традиционный кинжал стал обязательным атрибутом мужского костюма. Ни один уважающий себя и свой народ грузин или армянин не оденет национальный костюм, не прицепив на пояс кинжал. А некоторые арабские кочевники и до сих пор даже в обычной жизни не расстаются со старым и проверенным клинком. Читайте дальше про национальные кинжалы здесь.
Кинжалы в восточных единоборствах
В перечне основных видов оружия, которые применяются в популярном ныне ушу присутствуют кинжалы бишоу как в одиночном варианте дан бишоу (單匕首), так и в парном шуань бишоу (雙匕首).
Им характерны копьевидная форма клинка длиной 20-30 см и навершие в виде кольца или ложечки. До колец привязываются платочки, которые служат для отвлечения внимания противника. Отсутствие гарды компенсируется незаточенной и расширенной возле рукояти частью клинка.
Также в ушу используется и самый короткий меч цзянь, дуань цзянь (短剑), который, не будучи длиннее за бишоу, фактически из-за своих размеров тоже попадает в категорию кинжалов, сохраняя при этом гордый статус меча. Ну, а заодно, и форму меча. Прямой клинок, равномерно сужающийся только в области острия, и небольшая гарда отличают его от кинжала бишоу.
А в каратэ применяется клинок стилетного типа сай. Происхождение у него совсем не благородное, а прямо-таки «пролетарско-крестьянское», из сельскохозяйственного инструмента для рыхления земли. По форме он не то трезубец с короткими боковыми зубцами, не то стилет (круглый или многогранный) с длинными, загнутыми в сторону острия и дополнительно заточенными сторонами простой крестовидной гарды. Небольшая круглая головка навершия обеспечивает фиксацию руки от выскальзывания из нее рукояти. Такая форма роднит сай с благородной европейской дагой с той лишь разницей, что сай способен справиться и с более мощным клинком, чем шпага. Человек, владеющий техникой пользования саем, сможет успешно противостоять любому вооруженному противнику.
***
Читайте также статьи об уходе за кинжалом и о заточке лезвия.
Виды кинжалов Средневековья — Proshloe
Кинжалы сопровождали воинов с самых первых веков. За тысячи лет истории они много раз меняли свою форму, однако их главное назначение – убивать – оставалось неизменным.
Что касается кинжалов XI—XIII веков, то информации о них очень мало, хотя несколько экземпляров было найдено и они хорошо известны специалистам.
Гораздо больше примеров появляется, начиная с XIV века. В первую очередь это изображения и надгробные скульптуры, которые изображают погибших или умерших своей смертью рыцарей — разумеется, в полном вооружении.
Надо полагать, что в это время Европа переживала настоящий бум на кинжалы. И хотя все кинжалы разные, большинство из них можно вогнать в строгие рамки видов и типов. Их насчитывают пять.
1. Кинжал «баллок»
Про кинжал «баллок» мы подробно рассказали вот в этой статье. Не менее подробные статьи будут и об остальных видах кинжалов, так что будьте с нами!
Чтобы не пропустить наши новые статьи подпишитесь на нас по электронной почте.
Процесс подписки описан здесь
Форма подписки находится здесь.
Так вот. Оружие имеет два шаровых выступа у основания рукояти и потому называется «кинжал с яйцами» — «баллок» . В более поздние времена его могли называть «почечный кинжал», дабы не использовать «неприличную лексику» в обществе.
2. Кинжал «басселард»
Кинжал «басселард» отличался симметричной рукоятью в форме буквы «I», к которой так легко было приклепать костяные щечки.
Название за этим видом кинжалов закрепилось благодаря швейцарскому городу Базель. Именно там, как считается, они появились в конце XIII века. Примерно в XV столетии басселарды станут родоначальниками другого вида кинжалов — «гольбейн».
На этих кинжалах не сохранилась деревянная рукоять, однако до сих пор они весьма опасны.
Ранние басселарды затачивались только с одной стороны, как ножи. С течением времени популярность приобрела двусторонняя заточка.
3. Кинжал «квилон»
Квилон очень напоминает короткий рыцарский меч романского или готического типов. Отличие только в размере.
Кстати, зачастую меч и квилон могли изготавливаться в комплекте, с одинаковыми клинками и эфесами.
Появился квилон, как и баселлард, в XIII столетии, однако несколько раньше своего коллеги. Некоторые квилоны замечены на иллюстрациях так называемой Библии Мациевского, которая была изготовлена для короля-крестоносца Людовика IX. Книга датируется 1240-1250 годами, а значит, этот вид кинжала был уже очень хорошо знаком монахам-рисовальщикам.
На фото один из таких кинжалов-квилонов, изготовленный в первой половине XV столетия. Его длина 40 см, клинок заточен с двух сторон.
4. «Ушастый» кинжал
Этот вид кинжала имел своеобразную рукоять, с двумя выступами, эдакими «ушками». Они крепились вместо навершия, сперва параллельно, а затем все с большим и большим углом друг ко другу.
Место между ушами стало точкой упора большого пальца, в случае так называемого «обратного хвата» – когда клинок выходит из кулака со стороны мизинца. Таким образом, удар с упором большого пальца становился особенно сильным — кинжал как бы вколачивали в цель.
5. Кинжал «рондель»
Рондель это вид кинжала с двумя дисками вместо навершия и гарды. Эти-то диски и дали название оружию. Надо сказать, «рондель» это просто диск, а вовсе не обязательно часть кинжала. Например, ронделем принято называть круглую деталь наплечника рыцарских лат, которая бережет подмышку воина.
Разумеется, это не исчерпывающая классификация, но на нее вполне можно опираться. А если хотите подробностей – читайте «Людоту». Скоро будет 😉
Фото — Niels Provos
Кинжал «баллок» — самый мужской кинжал
В Средние века существовало несколько типов кинжалов. Каждый из них отличался от других формой своей рукояти:
- квилон представлял собой уменьшенную копию меча,
- симметричная рукоять баселарда напоминала латинскую «I»,
- у ронделя была плоская круглая гарда и такое же навершие,
- на рукояти ушастого кинжала выступали два круглых диска наподобие ушей,
- баллок характеризовался двумя круглыми выступами на гарде.
Слева направо: баллок, баселард, квилон, ушастый кинжал, рондель.
Название «баллок» происходит от фаллической формы его рукояти (два шарика на гарде объединены с черенком), а также от склонности воинов 14-го века к ношению кинжала прямо перед поясом. По-русски его название переводят как «кинжал с яйцами». Другое название, придуманное историками Викторианской эпохи — «почечный кинжал» — очевидная попытка преуменьшить сексуальный оттенок формы кинжала.
Баллок появился на изображениях около 1300-1350 годов, и история его использования является одной из самых продолжительных среди пяти основных типов средневековых кинжалов. На континенте он использовался в течение всего 16-го века, а в Англии его форма сохранилась и в 17-ом столетии в качестве «dudgeon dagger» или «кинжала-обидчика». Только в Шотландии баллок продолжали использовать на протяжении всего 18-го века, и мы знаем его под именем шотландского дирка.
Несколько примеров появления баллока в художественных работах.
Баллок использовался повсеместно в Европе всеми классами населения. Ранние изображения доказывают, что баллок изначально был рыцарским оружием. Более детальная проработка кинжалов, появившихся позже, подсказывает нам, что баллок становится также оружием торговцев и ремесленников. Безусловно, существовали очень простые и грубые варианты кинжалов, которые, по всей вероятности, использовались крестьянами.
Клинок
Виды клинков баллока отличаются значительным разнообразием. Одной из первых и наиболее распространенных форм его был односторонне заточенный клинок, имевший треугольную форму и равномерно сужавшийся от рукояти к острию. Иногда клинок для усиления прочности делали четырехугольным в сечении.
В начале 15-го века становятся популярными равномерно сужающиеся кромки лезвий. Ко второй половине 15-го столетия кромки лезвий становятся тоньше, они снабжаются толстым ромбовидным выступом и рикассо. (Рикассо — это часть клинка около гарды, которая не затачивается, и потому на нее можно положить палец.)
Этот более поздний вариант продолжал существование на протяжении всего 16-го века, а ромбовидный выступ на клинке становится настолько толстым, что клинок может рассматриваться как четырехгранный. Замечено, что такие четырехгранные лезвия были наиболее часто встречающейся формой в 16-м столетии.
Множество разнообразных видов клинка баллока.
Одним из видов баллока, который был узнаваем скорее по стилю клинка, нежели форме рукояти, был «кинжал-обидчик». В 17-ом веке эти клинки снабжались обилием гравировки и позолоты и равномерно сужались от рукояти к острию. Практически все они имели рикассо, а варианты без него были, скорее, исключением из правил.
Другие формы клинка, включая копии мечей, продолжали появляться на протяжении всего Средневековья, но это были единичные случаи, совсем не типичные для клинков баллока. Считать родственниками баллока можно только односторонне заточенные шотландские дирки 18-го столетия.
Каждый из представленных кинжалов имеет свой вид клинка.
Хотя форма клинка баллока менялась на протяжении всего периода их использования, длина его оставалась практически неизменной. В большинстве случаев длина клинка равнялась трем или четырем длинам рукояти, поэтому клинки были от 10 до 16 дюймов в длину, то есть 25 — 40 сантиметрам.
Конечно, как и любое другое оружие с такой долгой историей, баллок знал исключения из правил. Лучшие примеры попадаются на берегу Балтийского моря, датируются 16-м столетием и снабжены клинками, ненамного длиннее рукояти.
Рукоять
В своей ранней и простейшей форме рукоять баллока была сделана из единого куска древесины, такого как черное дерево, шиповник, вереск или падуб, без металлических частей.
Доли, которые сформировали гарду, были большими и хорошо закругленными, а черенок рукояти заканчивался округлой выпуклостью и мог сужаться в ту или иную сторону конусообразно.
В конечном итоге, для рукояти использовали и другие материалы, включая рог, кость а, в более поздних конструкциях, медь и даже агат. К началу 15-го тсолетия они стали снабжаться металлическими пластинами, которые укрепляли рукоять между гардой и клинком. Такая форма рукояти использовалась на протяжении всей жизни этого вида кинжалов.
Кинжалы с деревянными рукоятками.
В начале 15-го века появился другой тип баллоков и использовался одновременно с первоначальной формой. Выступы гарды остались прежними, но навершие переместилось вверх к форме перевернутого конуса. Оно заканчивалось плоским прикладом, который обычно покрывался металлической пластиной. Иногда на этой пластине гравировались геометрические узоры.
К концу 15-го века появилась третья форма рукояти. Она заканчивался плоским или немного закругленным навершием, которое могло — хотя и не обязательно, покрываться пластиной. Рукоять этого типа чаще всего была плоской, но есть и примеры граненых либо резных спиральных рукоятей.
Однако не только рукоять, но и гарда изменилась к началу 15-го века. У некоторых кинжалов появились 3 доли в гарде, вместо обычных двух. Кроме того, металлическая пластина, отделяющая гарду от клинка, стала толще, длиннее и ставилась с наклоном ко клинку, выдаваясь почти как на квилоне.
В северной Франции и Фландрии доли гарды делали из металла, а в Северной Германии не только доли, но и навершие в форме диска, так же было металлическим.
Кинжалы с металлическими выступами на ограничителях.В 16-м веке можно наблюдать всё ту же фаллическую форму кинжала с перевернутыми коническими навершиями. Однако обе формы увеличиваются, становятся более тонкими и впечатляющими.
Рукоять фаллической формы становится длиннее и почти столбчатой. Иногда они были рифлеными и часто гранеными.
Навершие оставалось выпуклым, но также часто коническим. Пока некоторые экземпляры оказались практически без навершия.
Доли гарды стали меньше и в форме полумесяца, и обычно клинок и гарду отделяла металлическая пластина. В этот период рукоять обычно изготавливалась из одного цельного куска материала.
В общем, баллоки с коническими навершиями следовали тем же тенденциям, что и их более фаллические коллеги. Исключение в развитии баллока было только в одном регионе – по берегам Балтийского моря.
Баллоки, названные Poke, Poeke, or Poicke, характеризовались фаллической формы рукоятью с коническим навершием, доли которого были закреплены на стержнях. Кинжал был обоюдоострый от навершия до наконечника клинка.
Разнообразие кинжалов-обидчиков.В Англии часто рукояти баллоков делали из самшита, которой также называли , поэтому иногда баллоки называют «кинжалами-обидчиками».
В 17-м веке рукоять «кинжала-обидчика» производилась из натурального самшита. В Англии его часто называли dudgeon («обидчик») -отсюда и пошло название кинжала. Рукоять его была очень похожа на фаллический тип рукояти кинжалов 16-го века, но стала длиннее. Кроме того, ее делали рифленой и / или граненой, шестиугольной или восьмиугольной в сечении.
Доли крестовины баллока сократились и образовали аккуратную серповидную форму. Она ограничивалась железной или стальной лентой перед рикассо, с гравировкой и позолотой, а так же укрепленным ромбовидным наконечником.
Последняя главная разновидность рукояти баллока появилась в 18-ом веке с развитием шотландского дирка. Базовая форма продолжала тенденции «кинжала-обидчика», включая меньшие доли, хотя они стали более сглаженными и удлиненными. В большинстве экземпляров всё также остаются металлические полосы между рукоятью и лезвием.
Однако, вместо фаллической формы, рукояти стали цилиндрическими, черенки получили плоское навершие, украшенное металлической пластиной. Обычно она делалась из латуни, но применялись и другие металлы, в том числе олово, серебро, и золото.
Рифление было заменено сложным переплетением рисунка или же рукоять украшалась мелкими гвоздиками. Конечно, очень простые гладкие рукояти также имели место в этот период.
Ранние шотландские дирки, имеющие формы баллоков.
Ножны
Ножны для баллоков были очень разнообразны, независимо от эпохи, когда они были сделаны. Иногда это был простой кожаный чехол без металлических креплений. Иногда они были из кожи с металлическими полосами для подвески. Существуют и деревянные ножны, покрытые кожей. Есть, по крайней мере, одни ножны, сделанные целиком из серебра.
В большинстве случаев, более поздние ножны имели металлическую горловину и очень длинную металлическую оковку. В дополнение ко всему, начиная с 1416 года и на протяжении всего 16-го века, они также имели карманы для маленьких дополнительных ножей, шила и других вспомогательных инструментов, которые подчеркивают утилитарную природу баллоков.
Баллок с ножнами, шилом и ножом, собрание Уолласа.
Как уже было замечено выше, в 14-ом веке баллок часто носили прямо перед поясом, оправдывая его название. Как бы там ни было, такое ношение не было универсальным. С гражданским платьем, как правило, баллок носили прямо позади поясного кошеля или же он просто свисал через поясную петлю.
В 15-ом веке кинжал чаще всего носили справа в горизонтальном положении или на поясе на спине. Подобно разнообразию ножен применялось и много способов ношения кинжала.
Исторические примеры
Здесь представлены примеры подлинных баллоков:
Музей Метрополитен, Нью-Йорк.
Прекрасный пример баллока классической формы, датируется поздним 15ым столетием и является французским или фламандским.
Королевская оружейная палата в Лидсе, Великобритания.
Этот экземпляр, вероятно, английский. Здесь изображена чрезвычайно сложная геометрия клинка с плоским незаточенным рикассо и ромбически заточеннным навершием. Цилиндрический черенок заканчивается сферическим навершием.
Музей Лондона.
Гражданский кинжал, датированный 1450 годом, с односторонне заточенным лезвием и большими защитными долями.
Находится в частной коллекции.
Найденный при раскопках фламандский кинжал датируется началом 17го века. Он снабжен односторонне заточенным лезвием треугольного сечения. Его деревянная рукоять с коническим захватом увенчана железным навершием в виде диска. Железные лопасти отделяют доли крестовины от клинка.
Находится в частной коллекции
Экземпляр 16го или 17го века, найденный в реке Темзе, фламандский или английский, длина 19,25 дюйма. Треугольный клиновидный клинок имеет одностороннюю заточку. Резная деревянная рукоять снабжена железным навершием.
Музей Метрополитен, Нью-Йорк.
Французский или фламандский экземпляр второй половины 15го века. Гарда состоит из трех долей, в отличие от обычных двух. Рукоять и навершие металлические.
Немецкий музей клинков.
Прекрасный немецкий образец второй половины 15го столетия. Изящная рукоять и декоративное навершие создают особый стиль.
Королевская оружейная палата в Лидсе, Великобритания.
«Кинжал–обидчик» длиной 15,5 дюймов является английской или шотландской работой и датируется примерно 1620 годом. По легенде, этим типом кинжала был вооружен полковник Томас Блад, когда он предпринял попытку украсть драгоценности Короны в 1671 году.
Находится в частной коллекции.
Кинжал фламандского происхождения конца 16-го — начала 17-го века. Прочное клиновидное лезвие имеет маркировку изготовителя. Деревянная рукоять является более поздней заменой и покрыта железным навершием.
Собрание Уоллеса.
Вероятно, фламандский кинжал второй половины 15-го века, в комплекте с шилом, ножом и ножнами.
Находится в частной коллекции.
Прекрасный французский или английский образец примерно 1470 года с резной костяной рукоятью с серебряными креплениями. Кинжал 17,75 дюймов в длину, лезвие 12,375 дюймов в длину. Дополнительные выступы гарды сделаны из стали. Клинок обоюдоострый ромбический в сечении.
Немецкий музей клинков.
Итальянский экземпляр 15-го века, произведение искусства с треугольным клинком, широко расширяющийся черенок заканчивается металлическим диском.
Находится в частной коллекции.
Редкий балок второй половины 15-го столетия, родом из Северной Европы, длиной 15,25 дюйма. Жесткий клинок ромбовидный в сечении у рукояти плавно перетекает в пятиугольное сечение. Бочковидной формы диск пустой, клинок у основания покрыт позолотой.
Находится в частной коллекции.
Еще один пример резко сужающегося клинка, датируется концом 14-го — началом 15-го столетия, снабжен длинным треугольным лезвием и усиленным наконечником. Рукоять состоит из резко расширяющегося хвата и металлического набалдашника. Общая длина составляет 15,25 дюймов.
Художественный музей Филадельфии.
Обнаруженный при раскопках экземпляр 15-го века, пример типичного однолезвийного клинка с рукоятью с дополнительными выступами.
Находится в частной коллекции.
Кинжал равнинных шотландцев, датирован 1610 годом. Длина 14,25 дюймов, 10-ти дюймовое вогнутое лезвие треугольное в сечении, инкрустировано медью. Восьмиугольное навершие на рукояти со спиральной канавкой. Доли гарды подверглись рифлению.
Местонахождение неизвестно.
Французского или фламандского происхождения кинжал, длина 15,5 дюймов. Черенок имеет форму гриба с латунной крышкой вместо навершия с изображением Богородицы с младенцем.
Музей Виктории и Альберта.
«Кинжал – обидчик», клинок которого датирован 1605 годом. На клинке — девиз «Ask me not for Schame, drink lis and by ane». Длина кинжала 15,25 дюйма. Обратите внимании на сложную геометрию клинка.
Находится в частной коллекции.
Длина 18 дюймов. Этот экземпляр, возможно, английского производства, датируется 1520 годом. Округлый черенок рукояти состоит из нескольких секций, на резко расширяющемся навершии латунный диск с гравировкой. Расплющенное лезвие имеет длинную ложную кромку.
Находится в частной коллекции.
Английский баллок с вогнутым клинком 17,25 дюйма, ромбический в сечении с желобом по всей длине. Черенок деревянной рукояти граненый со стальной полосой и латунным навершием.
Художественный музей Филадельфии.
Довольно редкий экземпляр с трехгранной рукоятью, расширяющимся черенком и трехгранным клинком. Кинжал обнаружен при раскопках в довольно плохом состоянии.
Музей Метрополитен, Нью-Йорк.
Датируется второй половиной 15-го века. Западноевропейский кинжал с заостренным лезвием, треугольный в сечении на протяжении всей длины. Однако его клинок заканчивается четырехгранным шилом. Черенок рукояти резной, деревянный, увенчан латунным навершием. Довольно большой экземпляр — длина 18 дюймов и вес 11 унций.
Королевская оружейная палата в Лидсе, Великобритания.
Баллок 15-го века с резным костяны
Использование Dagger в вашем приложении для Android
Из этой лаборатории вы узнаете о важности внедрения зависимостей (DI) для создания надежного и расширяемого приложения, масштабируемого для крупных проектов. Мы будем использовать Dagger в качестве инструмента DI для управления зависимостями.
Внедрение зависимостей (DI) — это метод, широко используемый в программировании и хорошо подходящий для разработки под Android. Следуя принципам DI, вы закладываете основу для хорошей архитектуры приложения.
Реализация внедрения зависимостей дает вам следующие преимущества:
- Возможность повторного использования кода.
- Легкость рефакторинга.
- Легкость тестирования.
Если вы столкнетесь с какими-либо проблемами (ошибки кода, грамматические ошибки, нечеткие формулировки и т. Д.) Во время работы с этой таблицей кодов, сообщите о проблеме с помощью ссылки Сообщить об ошибке в нижнем левом углу таблицы кодов.
Предварительные требования
- Опыт работы с синтаксисом Kotlin.
- Вы понимаете внедрение зависимостей и знаете, каковы преимущества использования Dagger в вашем приложении для Android.
Дополнительные сведения о внедрении зависимостей и о том, как Dagger помогает вам в приложении для Android, можно найти здесь:
- Основы внедрения зависимостей
- Внедрение зависимостей вручную в Android
- Преимущества использования Dagger в приложении для Android
Что вы узнаете
- Как масштабно использовать Dagger в приложении для Android.
- Соответствующие концепции Dagger для создания более надежного и устойчивого приложения.
- Зачем вам могут понадобиться субкомпоненты Dagger и как их использовать.
- Как протестировать приложение, использующее Dagger, с помощью модульных и инструментальных тестов.
К концу кодовой лаборатории вы создадите и протестируете граф приложения, подобный этому:
Стрелки представляют зависимости между объектами. Это то, что мы называем графом приложения : все классы приложения и зависимости между ними.
Продолжайте читать и узнайте, как это сделать!
Получить код
Получите код codelab с GitHub:
$ git clone https://github.com/googlecodelabs/android-dagger
Вы также можете загрузить репозиторий в виде Zip-файла:
Загрузить Zip
Откройте Android Studio
Если вам нужно загрузить Android Studio, вы можете сделать это здесь.
Создание проекта
Проект построен в нескольких ветках GitHub:
-
master
— это ветка, которую вы извлекли или загрузили.Отправная точка кодовой лаборатории. -
1_registration_main
,2_subcomponents
и3_dagger_app
являются промежуточными шагами к решению. -
solution
содержит решение этой codelab.
Мы рекомендуем вам шаг за шагом следовать кодовой лаборатории в своем собственном темпе, начиная с ветки master
.
Во время codelab вам будут представлены фрагменты кода, которые вы должны будете добавить в проект.В некоторых местах вам также придется удалить код, который будет явно упомянут и в комментариях к фрагментам кода.
В качестве контрольных точек у вас есть промежуточные ветви, доступные на случай, если вам понадобится помощь на определенном этапе.
Чтобы получить ветку решения с помощью git, используйте эту команду:
$ git clone -b решение https://github.com/googlecodelabs/android-dagger
Или загрузите код решения отсюда:
Скачать окончательный код
Часто задаваемые вопросы
Во-первых, давайте посмотрим, как выглядит стартовый пример приложения.Следуйте этим инструкциям, чтобы открыть образец приложения в Android Studio.
- Если вы скачали zip-архив, распакуйте файл локально.
- Откройте проект в Android Studio.
- Нажмите кнопку «Выполнить» и либо выберите эмулятор, либо подключите устройство Android. Должен появиться экран регистрации.
Приложение состоит из 4 различных потоков (реализованных как Действия):
- Регистрация : Пользователь может зарегистрироваться, указав имя пользователя, пароль и приняв наши условия.
- Вход в систему : пользователь может войти в систему, используя учетные данные, введенные в процессе регистрации, а также может отменить регистрацию в приложении.
- Домашняя страница : Пользователь приветствуется и может видеть, сколько у него непрочитанных уведомлений.
- Настройки : пользователь может выйти из системы и обновить количество непрочитанных уведомлений (что создает случайное количество уведомлений).
Проект следует типичному шаблону MVVM, в котором вся сложность представления возложена на ViewModel.Найдите минутку, чтобы ознакомиться со структурой проекта.
Стрелки представляют зависимости между объектами. Это то, что мы называем графом приложения : все классы приложения и зависимости между ними.
Код в ветке master
управляет зависимостями вручную. Вместо того, чтобы создавать их вручную, мы проведем рефакторинг приложения, чтобы использовать Dagger для управления ими за нас.
Заявление об ограничении ответственности
Эта лаборатория кода не зависит от того, как вы разрабатываете свое приложение.Он предназначен для демонстрации различных способов включения Dagger в архитектуру вашего приложения: одного Activity с несколькими фрагментами (потоки регистрации и входа) или нескольких Activity (основной поток приложения).
Заполните кодовую таблицу, чтобы понять основные концепции Dagger и соответствующим образом применить их в своем проекте. Некоторые шаблоны, используемые в этой таблице кодов, не являются рекомендуемым способом создания приложений для Android, однако они лучше всего объясняют Dagger.
Чтобы узнать больше об архитектуре приложений Android, посетите нашу страницу руководства по архитектуре приложений.
Почему кинжал?
Если приложение станет больше, мы начнем писать много шаблонного кода (например, с фабриками), который может быть подвержен ошибкам. Неправильное выполнение этого может привести к незначительным ошибкам и утечкам памяти в вашем приложении.
В кодовой лаборатории мы увидим, как использовать Dagger для автоматизации этого процесса и генерации того же кода, который в противном случае вы бы написали вручную.
Dagger будет отвечать за создание графа приложения для нас. Мы также будем использовать Dagger для внедрения поля в наши действия вместо создания зависимостей вручную.
Подробнее о Why Dagger здесь.
Чтобы добавить Dagger в свой проект, откройте файл app / build.gradle
и добавьте две зависимости Dagger и плагин kapt в начало файла.
приложение / build.gradle
применить плагин: 'com.android.application'
применить плагин: 'kotlin-android'
применить плагин: 'kotlin-android-extensions'
применить плагин: 'kotlin-kapt'
...
dependencies {
...
def dagger_version = "2.27"
реализация "ком.google.dagger: dagger: $ dagger_version "
kapt "com.google.dagger: dagger-compiler: $ dagger_version"
}
После добавления этих строк в файл нажмите кнопку «Синхронизировать сейчас», которая появляется в верхней части файла. Это синхронизирует проект и загрузит новые зависимости. Теперь мы готовы использовать Dagger в приложении.
Dagger реализован с использованием модели аннотаций Java. Он генерирует код во время компиляции с помощью процессора аннотаций. Процессоры аннотаций поддерживаются в Kotlin с помощью плагина компилятора kapt.Они активируются добавлением apply plugin: 'kotlin-kapt'
в начало файла под строкой apply plugin: 'kotlin-android-extensions'
.
В зависимостях библиотека dagger
содержит все аннотации, которые вы можете использовать в своем приложении, а dagger-compiler
— это процессор аннотаций, который сгенерирует для нас код. Последний не будет упакован в ваше приложение.
Вы можете найти последние доступные версии Dagger здесь.
Начнем рефакторинг потока регистрации для использования Dagger.
Для автоматического построения графа приложения для нас, Dagger должен знать, как создавать экземпляры для классов в графе. Один из способов сделать это — аннотировать конструктор классов с помощью @Inject
. Параметры конструктора будут зависимостями этого типа.
Откройте файл RegistrationViewModel.kt
и замените определение класса следующим:
RegistrationViewModel.кт
// @Inject сообщает Dagger, как предоставить экземпляры этого типа
// Dagger также знает, что UserManager является зависимостью
class RegistrationViewModel @Inject constructor (val userManager: UserManager) {
...
}
В Kotlin, чтобы применить аннотацию к конструктору, вам нужно специально добавить ключевое слово constructor
и ввести аннотацию непосредственно перед ним, как показано во фрагменте кода выше.
С аннотацией @Inject
Dagger знает:
- Как создать экземпляры типа
RegistrationViewModel
. -
RegistrationViewModel
имеетUserManager
в качестве зависимости, поскольку конструктор принимает в качестве аргумента экземплярUserManager
.
Для простоты, RegistrationViewModel
не является моделью ViewModel для компонентов архитектуры Android; это просто обычный класс, который действует как ViewModel.
Для получения дополнительной информации о том, как это можно использовать с Dagger, ознакомьтесь с официальной реализацией кода Android Blueprints.
Dagger еще не умеет создавать типы UserManager
.Выполните тот же процесс и добавьте аннотацию @Inject
в конструктор UserManager
.
Откройте файл UserManager.kt
и замените определение класса следующим:
UserManager.kt
class UserManager @Inject constructor (частное хранилище val: Storage) {
...
}
Теперь Dagger знает, как предоставить экземпляры RegistrationViewModel
и UserManager
.
Начиная с , зависимость UserManager
(т.е.е. Storage
) — это интерфейс, нам нужно указать Dagger, как создать его экземпляр другим способом, мы рассмотрим это позже.
Представлениям требуются объекты из графа
Определенные классы платформы Android, такие как Activity и Fragments, создаются системой, поэтому Dagger не может создать их для вас. В частности, для Activity любой код инициализации должен перейти к методу onCreate
. Из-за этого мы не можем использовать аннотацию @Inject
в конструкторе класса View, как мы это делали раньше (это то, что называется внедрением конструктора).Вместо этого мы должны использовать внедрение поля.
Вместо создания зависимостей, требуемых Activity, в методе onCreate
, как мы делаем с ручным внедрением зависимостей, мы хотим, чтобы Dagger заполнял эти зависимости за нас. Для внедрения полей (что обычно используется в Activity и Fragments) мы аннотируем поля @Inject
, которые мы хотим предоставить Dagger.
В нашем приложении RegistrationActivity
зависит от RegistrationViewModel
.
Если вы откроете RegistrationActivity.kt
, мы создадим ViewModel в методе onCreate
непосредственно перед вызовом supportFragmentManager
. Мы не хотим создавать его вручную, мы хотим, чтобы его предоставил Dagger. Для этого нам необходимо:
- Добавьте к полю аннотацию
@Inject
. - Удалите его экземпляр из метода
onCreate
.
RegistrationActivity.kt
class RegistrationActivity: AppCompatActivity () {
// Аннотированные поля @Inject будут предоставлены Dagger
@Inject
lateinit var registrationViewModel: RegistrationViewModel
переопределить веселье onCreate (savedInstanceState: Bundle?) {
...
// Удаляем следующую строку
registrationViewModel = RegistrationViewModel ((приложение как MyApplication) .userManager)
}
}
Когда @Inject
аннотируется в конструкторе класса, он сообщает Dagger, как предоставить экземпляры этого класса. Когда он аннотируется в поле класса, он сообщает Dagger, что ему необходимо заполнить поле экземпляром этого типа.
Как мы можем сказать Dagger, какие объекты нужно вставить в RegistrationActivity
? Нам нужно создать граф Dagger (или граф приложения) и использовать его для внедрения объектов в Activity.
Мы хотим, чтобы Dagger создавал граф зависимостей нашего проекта, управлял ими за нас и имел возможность получать зависимости из графа. Чтобы заставить Dagger это сделать, нам нужно создать интерфейс и аннотировать его с помощью @Component
. Dagger создаст контейнер, как если бы мы это делали с ручной инъекцией зависимостей.
Интерфейс с пометкой @Component
заставит Dagger генерировать код со всеми зависимостями, необходимыми для удовлетворения параметров методов, которые он предоставляет.Внутри этого интерфейса мы можем сообщить Dagger, что RegistrationActivity
запрашивает инъекцию.
Создайте новый пакет с именем di
под com.example.android.dagger
(на том же уровне, что и другие пакеты, такие как , регистрация
). Внутри этого пакета создайте новый файл Kotlin с именем AppComponent.kt
и определите интерфейс, как описано выше:
приложение / SRC / основной / Java / ком / пример / Android / кинжал / ди / AppComponent.kt
пакет com.example.android.dagger.di
импортировать com.example.android.dagger.registration.RegistrationActivity
импортный кинжал. компонент
// Определение компонента Dagger
@Составная часть
interface AppComponent {
// Классы, которые могут быть введены этим Компонентом
инъекция веселья (активность: RegistrationActivity)
}
С помощью метода inject (activity: RegistrationActivity)
в интерфейсе @Component
мы сообщаем Dagger, что RegistrationActivity
запрашивает инъекцию и что он должен предоставить зависимости, аннотированные с помощью @Inject (i.е. RegistrationViewModel
, как мы определили на предыдущем шаге)
Advanced Dagger 2 с Android и Kotlin
Изменения конфигурации Gradle
Для использования Dagger 2 с Kotlin необходимо использовать kapt
вместо annotationProcessor
(что работает в Java).
- Как настроить Kotlin с Android и Dagger 2. Установка
- Dagger 2 для Android с использованием Java , а не Kotlin.
Итак, в build.gradle
:
-
kapt
необходимо добавить как плагин -
annotationProcessor
необходимо заменить наkapt
применить плагин: 'kotlin-kapt'
dependencies {
доб.dagger2_version = '2.17'
// Базовый кинжал 2 (обязательно)
реализация "com.google.dagger: dagger: $ dagger2_version"
kapt "com.google.dagger: dagger-compiler: $ dagger2_version"
// пакет dagger.android (необязательно)
реализация "com.google.dagger: dagger-android: $ dagger2_version"
kapt "com.google.dagger: dagger-android-processor: $ dagger2_version"
// Поддержка библиотеки поддержки (необязательно)
kapt "com.google.dagger: dagger-android-support: $ dagger2_version"
}
Прицелы на заказ
Учебник
В этом руководстве подробно рассказывается, как использовать прицелы, и разъясняется, как простой механизм действительно есть.
Компонент, помеченный как аннотация
@Scope
, может иметь поставщиков модуля, помеченных как такой же объем.В
@Singleton
нет ничего особенного. Как и с любым другим прицелом, когда вы отмечаете компонент с аннотацией области действия, вы также должны отметить поставщика (ов) в модуль (и) с таким же. Другими словами, вы не можете смешивать области видимости. Для@Singleton
это означает создание компонента в Приложении, чтобы все объекты, предоставленные модулями, помеченными как w / this возможности доступны везде.Это просто условность.Идея использования настраиваемых областей позволяет упростить создание объектов и управление ими. на сторону компонента / модуля / поставщика. И простота предоставляется клиенту / потребителю сторона, где вы просто отмечаете поля, которые вам нужно ввести, используя
@Inject
, и это «просто работает»!
Учебник
- В этой статье подробно рассматривается код, сгенерированный
@Scope
, и то, что он делает на самом деле. под одеялом.Scope просто создает кэшированного провайдера.
- В этой статье подробно рассматривается код, сгенерированный
Учебник
- В этой статье представлен сложный пример нескольких областей и подкомпонентов.
SO
- Это обсуждение stackoverflow отлично подходит для создания более сложных подкомпонентов.
Создание и использование настраиваемой области
Вот пример настраиваемой области под названием @ActivityScope
.Синтаксис для Java совершенно другой
чем Котлин.
@Scope
@ kotlin.annotation.Retention (AnnotationRetention.RUNTIME)
класс аннотации ActivityScope
Вот эквивалент в Java.
@Scope
@Retention (RetentionPolicy.RUNTIME)
public @interface ActivityScope {}
Мы используем настраиваемую область, когда хотим повторно использовать зависимости в течение определенного промежутка времени. Например, @ActivityScope
выше может использоваться для зависимостей, которые должны быть доступны только для
жизненный цикл
в Android с помощью Dagger 2 и Kotlin
Примечание об обновлении : этот учебник Dagger 2 теперь обновлен до последней версии Android Studio версии 3.0.1 и использует Kotlin для разработки приложений. Обновление Дарио Колетто. Оригинальный учебник Джо Ховарда.
Оказывается, внедрение зависимостей далеко не так сложно, как следует из названия. И это ключевой инструмент для создания программных систем, поддерживаемых и тестируемых. В конце концов, полагаясь на инъекцию зависимостей, вы немного упростите ваш код, а также предоставите более четкий путь к написанию тестируемого кода.
В этом руководстве вы обновите существующее приложение с именем DroidWiki для использования DI. Приложение DroidWiki — это простой клиент Википедии для Android, основанный на Dagger 2 и OkHttp 3 . API Википедии основан на MediaWiki, и вы можете найти здесь документацию. Эти API являются общедоступными, и нет необходимости получать ключи API или другие вещи. Но вам обязательно стоит ознакомиться с MediaWiki Etiquette.
Вот быстрый взгляд на экран результатов поиска в DroidWiki:
Введение
Прежде чем мы начнем, если вы не знаете, что такое внедрение зависимостей, вот вам отличная новость: вы, вероятно, уже используете его, даже не подозревая об этом!
Что такое внедрение зависимостей?
Во-первых, что такое зависимость? Любая нетривиальная программа будет содержать компоненты, которые передают информацию и отправляют вызовы сообщений между собой.
Например, при использовании языка объектно-ориентированного программирования (такого как Java / Kotlin на Android) объекты будут вызывать методы других объектов, на которые они ссылаются. Зависимость — это когда один из объектов зависит от конкретной реализации другого объекта.
Практический пример внедрения зависимостей
Рассмотрим практический пример в коде Kotlin. Вы можете идентифицировать зависимость в своем коде всякий раз, когда вы создаете экземпляр объекта внутри другого.В таком случае вы несете ответственность за создание и настройку создаваемого объекта. Например, рассмотрим следующий класс Parent
:
class Parent {
частный val child = Child ()
}
При создании экземпляра Parent
создается его дочернее поле
. Экземпляр Parent
зависит от конкретной реализации Child
и от настройки поля child
для его использования.
Представляет -связь или класса Parent
с классом Child
. Если настройка объекта Child
является сложной, вся эта сложность также будет отражена в классе Parent
. Вам нужно будет отредактировать Parent
, чтобы настроить объект Child
.
Если класс Child
сам зависит от класса C
, который, в свою очередь, зависит от класса D
, то вся эта сложность будет распространяться по всей кодовой базе и, следовательно, приведет к тесной связи между компонентами приложения.
Внедрение зависимости — это термин, используемый для описания только что описанной техники ослабления сцепления. В приведенном выше простом примере требуется только одно крошечное изменение:
.
class Parent (частный потомок val: Ребенок)
Voilà — это внедрение зависимостей по своей сути!
Вместо создания дочернего объекта
внутри класса Parent
, дочерний объект
передается или внедряется в конструктор Parent
.Ответственность за настройку дочернего
лежит где-то еще, а класс Parent
является потребителем класса Child
.
Принцип инверсии зависимостей
Внедрение зависимостей часто обсуждается в связи с одним из пяти принципов SOLID объектно-ориентированного проектирования: принципом инверсии зависимостей . Чтобы получить отличное представление о принципах SOLID, особенно на Android, ознакомьтесь с этим сообщением Realm on Dependency Inversion.
Суть принципа инверсии зависимостей заключается в том, что важно полагаться на абстракции, а не на конкретные реализации.
В приведенном выше простом примере это означает изменение Child
на интерфейс Kotlin , а не на класс
Kotlin . С этим изменением многие различные типы конкретных объектов типа
Child
, которые соответствуют интерфейсу Child
, могут быть переданы в конструктор Parent
. Это дает несколько ключевых преимуществ:
- Позволяет тестировать класс
Parent
с различными типами объектовChild
. - Mock
Дочерние объекты
могут использоваться по мере необходимости в определенных тестовых сценариях. - Тестирование
Parent
не зависит от реализацииChild
.
Как Dagger 2 может помочь с DI
Dagger 2 - результат сотрудничества команды Guice (разработанной Google) и Dagger (предшественницы Dagger 2, созданной Square).
Они исправили множество проблем из своей предыдущей работы, и Dagger 2 является более быстрой структурой для DI (поскольку он работает во время компиляции, а не во время выполнения с отражением).
Примечание: Dagger 2 написан на Java, но работает с Kotlin без каких-либо изменений. Однако код, сгенерированный процессором аннотаций, будет кодом Java (который на 100% совместим с Kotlin).
Название «Dagger» отчасти связано с природой зависимостей в разработке программного обеспечения. Сеть зависимостей, которые возникают между такими объектами, как Parent
, Child
, OtherClass
и т. Д., Создают структуру, называемую направленным ациклическим графом .Dagger 2 используется для упрощения создания таких графиков в ваших проектах Java и Android.
Довольно теории! Пора начать писать код.
Начало работы
Загрузите стартовый проект здесь.
Откройте стартовое приложение в Android Studio 3.0.1 или выше, и если оно предложит вам обновить версию Gradle, продолжайте и сделайте это. Запустите стартовое приложение в эмуляторе или на устройстве, и вы должны увидеть экран, подобный следующему:
Приложение состоит из трех экранов.Первый - это просто заставка.
На втором вы увидите HTML-версию домашней страницы Википедии, полученную через WikiMedia API. Панель инструментов
вверху страницы содержит лупу, при нажатии на которую вы попадете на третий экран.
Оттуда вы можете ввести что-нибудь для поиска в Википедии и нажать кнопку поиска, чтобы выполнить запрос. Результаты будут отображаться в виде списка CardView
s внутри RecyclerView
.
Изучите структуру проекта приложения и существующие классы.Вы увидите, что приложение использует шаблон Model-View-Presenter (MVP) для структурирования кода. Помимо Dagger 2, приложение использует общие библиотеки Android, такие как:
Подпакеты в основном пакете: application
, model
, network
, ui
и utils
. Если вы изучите пакет ui
, вы увидите подпакеты для трех экранов. За исключением заставки, каждый другой пакет имеет классы для представления и классы презентатора для экрана.
Изучив файл app build.gradle , вы также увидите, что приложение применяет подключаемый модуль kotlin-android-extensions . Он используется для реализации привязки представления и kotlin-kapt для обработки аннотаций.
MVP
Если вы не знакомы с шаблоном MVP, есть много хороших онлайн-ресурсов для начала.
MVP похож на другие структурные шаблоны для реализации разделения проблем .Примеры: Model-View-Controller и Model-View-ViewModel . В MVP на Android ваши действия и фрагменты обычно действуют как объекты view . Они делают это за счет реализации интерфейса просмотра и обработки взаимодействия приложения с пользователем.
Представление передает действия пользователя презентатору , который обрабатывает бизнес-логику и взаимодействие с репозиториями данных, такими как серверный API или база данных. Слой model состоит из объектов, составляющих содержимое приложения.
В случае DroidWiki класс HomepageActivity
реализует интерфейс HomepageView
. HomepageActivity
имеет ссылку на интерфейс HomepagePresenter
. Это контролирует доступ к объектам модели типа Домашняя страница
Использование OkHttp 3 находится в классе WikiApi
в сетевом пакете
. Этот класс определяет интерфейс API WikiMedia, необходимый для приложения. Определены два вызова типа GET , и JSONObject
позволит вам проанализировать полученные ответы.Синтаксический анализ будет выполнен в классах HomepageResult
и SearchResult
. И вы получите объект WikiHomepage
и список объектов Entry
.
Зависимости в DroidWiki
Откройте класс HomepageActivity
в пакете ui.homepage
. В методе onCreate ()
есть несколько вызовов для настройки HomepagePresenter
:
частный докладчик val: HomepagePresenter = HomepagePresenterImpl ()
...
presenter.setView (это)
presenter.loadHomepage ()
Здесь вы создаете конкретную реализацию HomepagePresenter
при создании экземпляра действия.
Откройте HomepagePresenterImpl.kt и посмотрите loadHomepage ()
. И объект OkHttpClient
, и объект WikiApi
создаются и настраиваются в методе loadHomepage ()
. То же самое происходит с SearchActivity
с EntryPresenter
и списком EntryView
.
Это создание зависимостей слишком тесно связывает уровни модели, представления и презентатора. Замена имитационного презентатора на представление невозможно, как написано, без обновления кода представления. Код для создания объектов OkHttpClient
и WikiApi
повторяется между двумя реализациями презентатора в приложении: HomepagePresenterImpl
и EntryPresenterImpl
.
Наконец, пора начать писать код, чтобы убрать дублирование кода и некоторую связь между слоями!
Сконфигурируйте проект с помощью Dagger 2
Настройка Dagger с помощью Kotlin немного отличается от того, как вы это делали с Java.Для
Dagger требуется процессор аннотаций , поэтому основное различие заключается в том, какой из них вы собираетесь использовать. Фактически, с Java вы использовали методы Groovy apt
или более новый annotationProcessor
, а с Kotlin вам нужно использовать kapt
.
По умолчанию kapt не включен в Kotlin, и чтобы включить его, вы должны применить его плагин к своему приложению build.gradle , поэтому добавьте строку apply plugin: 'kotlin-kapt'
:
применить плагин: 'com.android.application '
применить плагин: 'kotlin-android'
// Добавляем эту строку, чтобы включить kapt
применить плагин: 'kotlin-kapt'
...
Затем добавьте эти зависимости, чтобы фактически «установить» кинжал
dependencies {
...
реализация 'com.google.dagger: dagger: 2.11'
kapt 'com.google.dagger: dagger-compiler: 2.11'
предоставлен 'javax.annotation: jsr250-api: 1.0'
...
}
Здесь мы используем Dagger 2.11, вы можете проверить последнюю версию в репозитории Maven.
Android Studio предложит вам синхронизировать файлы Gradle при этом изменении, поэтому, пожалуйста, сделайте это, чтобы убедиться, что вы правильно включаете Dagger. Обратите внимание, что вы включаете библиотеку аннотаций из javax
, потому что многие функции Dagger предоставляются Java annotations .
Dagger 2 общедоступные API
Dagger 2 может показаться сложным вначале, но на самом деле это не так уж и сложно. Фактически, полный общедоступный API-интерфейс Dagger состоит менее чем из 30 строк кода.И из этих строк вы можете удалить пару интерфейсов, которые редко используются (Lazy и MapKey), поэтому наиболее часто используемые общедоступные API состоят из 3 аннотаций:
public @interface Component {
Класс > [] Modules () по умолчанию {};
Класс > [] Dependencies () default {};
}
public @interface Module {
Класс > [] Includes () default {};
}
public @interface Provides {}
Теперь давайте посмотрим, как эти аннотации используются для внедрения зависимостей в ваши проекты!
Модуль
Первая аннотация, которую вы будете использовать, - это аннотация @Module
.Начните с создания нового пакета с именем dagger
в главном пакете приложения, щелкнув правой кнопкой мыши основной пакет и выбрав New / Package :
Затем создайте новый файл в пакете dagger
. Щелкните правой кнопкой мыши dagger и выберите New / Kotlin File / Class . Назовите класс AppModule
.
Добавьте в новый файл следующий пустой класс:
@Module
class AppModule {
}
Здесь вы создали класс с именем AppModule
и аннотировали его аннотацией Dagger @Module
.Android Studio должна автоматически создать для вас все необходимые операторы импорта. Но если нет, нажмите option + return на Mac или Alt + Enter на ПК, чтобы создать их по мере необходимости.
Аннотация @Module
сообщает Dagger, что класс AppModule
предоставит зависимости для части приложения. Наличие в проекте нескольких модулей Dagger - это нормально, и один из них обычно предоставляет зависимости для всего приложения.
Добавьте эту возможность сейчас, вставив следующий код в тело класса AppModule
:
@Module
class AppModule (частное приложение val: приложение) {
@Provides
@Singleton
весело provideContext (): Контекст = приложение
}
Вы добавили частное поле для хранения ссылки на объект app
, конструктор для настройки app
и метод provideContext ()
, который возвращает объект app
.Обратите внимание, что для этого метода есть еще две аннотации Dagger: @Provides
и @Singleton
.
@Provides и @Singleton
Аннотация @Provides
сообщает Dagger, что метод предоставляет определенный тип зависимости, в данном случае объект Context
. Когда часть приложения запрашивает, чтобы Dagger внедрил Context
, аннотация @Provides
сообщает Dagger, где его найти.
Примечание: Имена методов для поставщиков, такие как provideContext ()
, не важны, и их можно назвать как угодно.Dagger смотрит только на возвращаемый тип. Использование в качестве префикса
является общепринятым соглашением.
Аннотация @Singleton
не является частью Dagger API. Он содержится в пакете javax, который вы добавили в build.gradle в начале. Он сообщает Dagger, что должен быть только один экземпляр этой зависимости. Таким образом, при генерации кода Dagger будет обрабатывать всю логику за вас, и вы не будете писать весь шаблонный код, чтобы проверить, доступен ли уже другой экземпляр объекта.
Компонент
Теперь, когда у вас есть модуль Dagger, содержащий зависимость, которую можно внедрить, как вы его используете?
Это требует использования другой аннотации Dagger, @Component
. Как вы сделали для AppModule, создайте новый файл Kotlin в пакете dagger
и назовите его AppComponent
.
Добавьте в файл следующий код:
@Singleton
@Component (модули = [AppModule :: class])
интерфейс AppComponent
Вы сказали Dagger, что AppComponent
- это одноэлементный компонентный интерфейс для приложения.Аннотация @Component
принимает на вход список из модулей
. Вы используете синтаксис литерального массива, доступный в Kotlin, [AppModule :: class]
.
Компонент используется для подключения объектов к их зависимостям, обычно с помощью переопределенных методов inject ()
. Чтобы использовать компонент, он должен быть доступен из частей приложения, которым требуется внедрение. Обычно это происходит из подкласса приложения Application
следующим образом.
Сначала добавьте следующее поле в WikiApplication
:
lateinit var wikiComponent: AppComponent
Теперь вы должны инициализировать AppComponent
. Сделайте это, добавив следующий метод в WikiApplication
:
частное развлечение initDagger (приложение: WikiApplication): AppComponent =
DaggerAppComponent.builder ()
.appModule (AppModule (приложение))
.build ()
Вы, вероятно, заметите ошибку, вызываемую Android Studio на DaggerAppComponent
.Щелкните Make Module ‘app’ из меню Android Studio Build . Будет создан новый файл с именем DaggerAppComponent.java
Импортируйте сгенерированный DaggerAppComponent
, чтобы удалить ошибки компиляции. Игнорируйте предупреждение об устаревании метода appModule ()
; это будет скоро исправлено.
Наконец, обновите onCreate ()
в WikiApplication
, чтобы он выглядел следующим образом:
override fun onCreate () {
супер.onCreate ()
wikiComponent = initDagger (это)
}
Инициализирует поле wikiComponent
при первом запуске приложения.
Ваша первая (зависимая) инъекция
Добавьте следующее объявление метода в интерфейс AppComponent
:
инъекция веселья (цель: HomepageActivity)
Здесь вы указали, что класс HomepageActivity
потребует внедрения из AppComponent
.
Создайте новый класс в пакете dagger
и назовите его PresenterModule
. Добавьте следующий код в PresenterModule
:
@Module
class PresenterModule {
@Provides
@Singleton
весело provideHomepagePresenter (): HomepagePresenter = HomepagePresenterImpl ()
}
Вы указываете, что будет предоставлен HomepagePresenter
, а возвращаемый презентатор будет конкретной реализацией HomepagePresenterImpl
.
Затем подключите PresenterModule
к AppComponent
, обновив аннотацию @Component
в AppComponent
, чтобы она читалась:
@Component (модули = [AppModule :: class, PresenterModule :: class])
Обновить домашнюю страницу Наконец, откройте класс HomepageActivity
в пакете ui.homepage
.
Вам необходимо обновить поле presenter
со следующими изменениями:
- удалить модификатор private (Dagger не может вводить частные поля)
- добавить аннотацию
@Inject
- добавить модификатор lateinit
- заменить val на var
- удалить инициализацию
Когда вы закончите, объявление presenter
будет выглядеть так:
@Inject lateinit var presenter: HomepagePresenter
Опять же, аннотация @Inject
не является частью Dagger; он принадлежит к аннотациям javax .
Аннотация @Inject
сообщает Dagger, что вы хотите, чтобы он сделал инъекцию поля presenter .
Обновите onCreate ()
, добавив вызов AppComponent.inject ()
следующим образом:
переопределить веселье onCreate (savedInstanceState: Bundle?) {
super.onCreate (savedInstanceState)
setContentView (R.layout.activity_homepage)
(приложение как WikiApplication) .wikiComponent.inject (это)
...
}
Вы получаете AppComponent
из WikiApplication
и просите его внедрить все известные зависимости в HomepageActivity
. Поскольку вы аннотировали ведущего
с помощью @Inject
, Dagger внедрит конкретный объект HomepagePresenter
в HomepageActivity
.
Dagger знает, что вы определили provideHomepagePresenter ()
в классе PresenterModule
, и использует его для создания внедренного объекта HomepagePresenter
.
Создайте и запустите приложение прямо сейчас. Он должен вести себя точно так же, как и раньше, и вы избежали исключения. Вы только что закончили свою первую инъекцию зависимостей с помощью Dagger 2!
Общий образец
Существует общая закономерность, которая возникает на основе предыдущих изменений кода. Подумайте о шагах, предпринятых для использования внедрения зависимостей Dagger с HomepageActivity
:
- Добавить
inject ()
в AppComponent
с аргументом HomepageActivity
. - Добавить
provideHomepagePresenter ()
в PresenterModule
. - Добавить аннотацию
@Inject
к домашней странице Презентатор
на домашней странице Активность
. - Добавить
WikiApplication.wikiComponent.inject (this)
в onCreate ()
в HomepageActivity
.
Если вы рассматриваете HomepageActivity
как целевой класс и HomepagePresenter
как исходный интерфейс, который нужно внедрить, то вышеуказанные шаги можно обобщить следующим образом для любого целевого класса, требующего внедрения исходных интерфейсов:
- Добавить
inject ()
в AppComponent
с аргументом класса Target
. - Добавьте аннотированный метод
@Provides
в PresenterModule
для каждого исходного объекта, который нужно внедрить. - Добавьте аннотацию
@Inject
к каждой переменной-члену Source
в классе Target
. - Добавьте
WikiApplication.wikiComponent.inject (this)
в onCreate ()
в Target
class.
В качестве задачи посмотрите, сможете ли вы выполнить внедрение подробного экрана EntryPresenter
в SearchActivity
.Это будет включать удаление следующей строки кода:
частный докладчик val: EntryPresenter = EntryPresenterImpl ()
Действия такие же, как и для HomepageActivity
. Используйте шаблон, и если вы застряли, ознакомьтесь с окончательным кодом проекта в конце этого руководства.
Внедрение сетевого графа
В приложении, как написано в настоящее время, презентаторы экрана списка и экрана подробных сведений создают свои собственные сетевые зависимости.В типичном приложении, которое использует Dagger 2 и OkHttp 3 вместе, OkHttp будет предоставляться путем внедрения зависимостей.
Здесь вы увидите некоторые из многих преимуществ использования внедрения зависимостей и Dagger 2, в том числе:
- Устранение дублирования кода.
- Устранение необходимости в настройке зависимостей.
- Автоматическое построение графа зависимостей.
Сетевой модуль
Начните с создания нового файла в пакете dagger
, на этот раз с именем NetworkModule
, который начинается следующим образом:
@Module
class NetworkModule {
}
Здесь вам нужно внедрить объект WikiApi
в реализации презентатора приложения, чтобы презентаторы могли вызывать API.
Например, если вы посмотрите на текущий HomepagePresenterImpl
, вы увидите, что WikiApi
зависит от объекта OkHttpClient
, и если вам нужна сложная настройка для HTTP-клиента, вам нужно будет настраивать OkHttpClient
каждые время (например, если вы хотите включить ведение журнала с помощью LoggingInterceptor
).
Кроме того, WikiApi
требует 3 строки, которые представляют:
- протокол запроса (HTTP или HTTPS)
- — язык запрашиваемой Википедии.
- остальная часть базового URL-адреса API Википедии (wikipedia.org/w/api.php)
Упрощение построителя API
Для простоты вы собираетесь объединить все эти 3 строки в одном провайдере .
Начните с добавления этого метода в NetworkModule
вместе с постоянной строкой:
companion object {
private const val NAME_BASE_URL = "NAME_BASE_URL"
}
@Provides
@ Имя (NAME_BASE_URL)
весело provideBaseUrlString () = "$ {Const.ПРОТОКОЛ}: // $ {Const.LANGUAGE}. $ {Const.BASE_URL} "
Здесь вы можете увидеть аннотацию @Named
, которая, опять же, не является частью Dagger, но предоставляется javax .
Вы вводите объект String
, и, поскольку String
является наиболее распространенным типом для использования в приложении для Android, вы воспользовались аннотацией @Named
, чтобы указать конкретную строку, которая должна быть предоставлена. Этот же метод можно использовать для ваших собственных типов, если вам нужно ввести несколько вариантов.
Теперь, когда у вас есть строка String
, представляющая базовый URL, добавьте следующее в конец NetworkModule
:
@Provides
@Singleton
весело provideHttpClient () = OkHttpClient ()
@Provides
@Singleton
весело provideRequestBuilder (@Named (NAME_BASE_URL) baseUrl: String) =
HttpUrl.parse (baseUrl) ?. newBuilder ()
@Provides
@Singleton
весело provideWikiApi (клиент: OkHttpClient, requestBuilder: HttpUrl.Строитель?) = WikiApi (клиент, requestBuilder)
Вы предоставляете HTTP-клиент, конструктор запросов и WikiApi
.
WikiModule
Затем создайте новый файл в пакете dagger
с именем WikiModule и добавьте методы предоставления для API:
@Module
class WikiModule {
@Provides
@Singleton
fun provideHomepage (api: WikiApi) = Домашняя страница (api)
@Provides
@Singleton
fun provideWiki (api: WikiApi) = Wiki (api)
}
В NetworkModule вы добавили методы обеспечения для объекта OkHttpClient
, HttpUrl.Builder
объект и WikiApi
объект. Затем в WikiModule вы добавили методы для объектов Homepage
и Wiki
, запрашивая зависимости от предыдущих методов.
Это позволяет Dagger построить граф зависимостей, так что, например, когда объект запрашивает для внедрения объект Wiki
, Dagger сначала предоставит WikiApi
, а затем OkHttpClient
и HttpUrl.Builder . начиная с provideWiki (api: WikiApi)
.
Dagger продолжит движение вверх по графику, чтобы найти baseUrl
для provideRequestBuilder (@Named (NAME_BASE_URL) baseUrl: String)
.
При использовании аннотаций @Singleton
будет создан только один экземпляр объектов WikiApi
и OkHttpClient
, который будет использоваться обоими действиями в приложении.
Добавьте ваш NetworkModule
и WikiModule
в AppComponent
, обновив аннотацию @Component
до следующего:
@Component (модули = [
AppModule :: класс,
PresenterModule :: класс,
NetworkModule :: класс,
WikiModule :: class])
Обновить PresenterModule
Затем обновите методы предоставления PresenterModule
, чтобы Context
передавался в качестве аргумента конструктора:
@Provides
@Singleton
fun provideHomepagePresenter (домашняя страница: Homepage): HomepagePresenter = HomepagePresenterImpl (домашняя страница)
@Provides
@Singleton
весело provideEntryPresenter (wiki: Wiki): EntryPresenter = EntryPresenterImpl (wiki)
И, конечно же, обновите конструкторы HomepagePresenterImpl
и EntryPresenterImpl
:
class HomepagePresenterImpl @Inject constructor (частная домашняя страница val: Homepage): HomepagePresenter {
...
}
class EntryPresenterImpl @Inject constructor (private val wiki: Wiki): EntryPresenter {
...
}
Домашняя страница / Wiki
конструкторам требуется параметр WikiApi
, но нам больше не нужно его предоставлять, так как Dagger внедрит его, поскольку он присутствует на его графике. На этом этапе вы можете удалить инициализацию:
частный клиент val: OkHttpClient = OkHttpClient ()
частный val api: WikiApi = WikiApi (клиент)
частная домашняя страница val: Homepage = Homepage (api)
частный клиент val: OkHttpClient = OkHttpClient ()
частный val api: WikiApi = WikiApi (клиент)
частная вики val: Wiki = Wiki (api)
Вы внедрили зависимость WikiApi
в докладчиков.Это позволило удалить дублированное создание объектов OkHttpClient
и WikiApi
.
Обновление WikiApi
В качестве последнего шага классу WikiApi
требуется конструктор с введенным параметром, поэтому вы должны его обновить:
class WikiApi @Inject constructor (частный клиент val: OkHttpClient, частный клиент val requestBuilder: HttpUrl.Builder?) {
...
}
Теперь вам не нужно создавать HttpUrl.Builder
каждый раз больше, поэтому вы можете обновлять методы getHomepage () / search (query: String)
:
val urlBuilder = requestBuilder
? .addQueryParameter (...)
...
Теперь все должно быть готово к работе. Создавайте и запускайте приложение и наслаждайтесь красотой развязанного внедренного кода!
Куда идти дальше?
Вы можете скачать финальный проект здесь.
Многие разработчики задаются вопросом, полезны ли все изменения, внесенные вами в приложение DroidWiki, или нет.Тем более, что до внедрения зависимостей все уже работало. Полезность внедрения зависимостей и фреймворка, такого как Dagger 2, наиболее очевидна в реальных производственных приложениях, где граф зависимостей может стать очень сложным.
Dagger 2 и внедрение зависимостей становятся особенно полезными при реализации надлежащего тестирования в вашем приложении, позволяя использовать имитирующие реализации серверных API и репозиториев данных при тестировании.
О Dagger 2 и его использовании можно узнать гораздо больше, в том числе:
- Области применения
- Компоненты
- Тестирование с Mockito
В Интернете есть много отличных ресурсов, чтобы погрузиться в эти темы, и один, который я должен, предложить, — это доклад Джейка Уортона на DevOxx, где вы можете получить дополнительную информацию об истории DI на Android, немного теории и несколько хороших примеров.Как и вы, счастливых инъекций!
Если у вас есть вопросы или комментарии, присоединяйтесь к обсуждению ниже!
raywenderlich.com Еженедельный
Информационный бюллетень raywenderlich.com — это самый простой способ оставаться в курсе всего, что вам нужно знать как разработчику мобильных приложений.
Получайте еженедельный дайджест наших руководств и курсов, а в качестве бонуса получите бесплатный углубленный курс по электронной почте!
. Dagger 2. Часть третья. Новые возможности | Евгений Мацюк
Dagger 2 цикл статей:
- Dagger 2. Часть I. Основные принципы, зависимости графиков, области видимости.
- Кинжал 2. Часть II. Пользовательские области, зависимости компонентов, подкомпоненты.
- Кинжал 2. Часть третья. Новые возможности.
Всем привет! Наконец-то вышла третья статья о Dagger 2!
Огромное спасибо за ваши отзывы и комментарии. Я очень рад, что эта серия статей поможет вам погрузиться в мир Dagger.Это источник силы и мотивации продолжать писать дальше.
В этой третьей части мы рассмотрим различные интересные и важные функции библиотеки, которые могут вам понадобиться в будущем.
Хотя библиотека существует довольно давно, ее документация по-прежнему очень плохая. Тем разработчикам, которые только начинают знакомство с Dagger, я бы посоветовал не заглядывать в официальную документацию, чтобы не разочароваться в этом жестком и несправедливом мире.
Безусловно, есть детали, которые освещены более-менее основательно. Однако для всех новых функций отсутствует надлежащая документация, поэтому мне пришлось буквально погрузиться в сгенерированный код, чтобы понять, как все работает. К счастью, есть молодцы, которые пишут хорошие статьи, но даже они иногда не дают четкого и резкого ответа.
Итак, хватит разглагольствования, вперед к новым знаниям!
Часто бывает, что нам нужно предоставить несколько объектов одного типа.Например, мы хотим иметь в системе два Executors : один однопоточный, а другой с CachedThreadPool . В таких случаях будет очень кстати «аннотация квалификатора». Это настраиваемая аннотация с аннотацией @Qualifier . Это звучит немного как «соль соленая», но все намного проще.
По сути, Dagger2 уже предоставляет нам одну «аннотацию квалификатора», которой, возможно, вполне достаточно для большинства случаев:
Теперь посмотрим, как это выглядит в действии:
В результате у нас есть два разных экземпляра ( singleExecutor , multiExecutor ) одного класса ( Executor ).Это именно то, что нам нужно! Обратите внимание, что объекты одного класса с аннотацией @Named также могут быть предоставлены как совершенно разными и независимыми компонентами, так и зависимыми.
Одна из частых проблем разработки — долгий запуск приложения. Обычно причина одна — мы загружаем слишком много и инициализируемся при запуске. Кроме того, Dagger2 строит граф зависимостей в основном потоке. Но часто не все предметы, предоставляемые Dagger, требуются немедленно.Таким образом, библиотека позволяет отложить инициализацию объекта до первого вызова с использованием интерфейсов Provider <> и Lazy <> .
Давайте посмотрим на следующий пример:
Начнем с Provider singleExecutorProvider . До первый вызов из singleExecutorProvider.get () Dagger не инициализирует соответствующий Executor . Но с каждый последующий вызов на singleExecutorProvider.get () будет создан новый экземпляр. Таким образом, singleExecutor и singleExecutor2 — это два разных объекта. Это поведение по существу идентично поведению объекта без области видимости .
Так в каких случаях уместен провайдер ? Это удобно, когда мы предоставляем какую-то изменяемую зависимость, которая со временем меняет свое состояние, и с каждым вызовом нам нужно получать текущее состояние. «Что это за кривая архитектура?» — скажете вы, и я с вами соглашусь.При работе с устаревшим кодом вы часто видите что-то подобное.
Стоит отметить, что авторы библиотеки также советуют не злоупотреблять интерфейсом Provider там, где достаточно обычного незаданного поставщика , так как это может привести к вышеупомянутой «кривой архитектуре» и затруднениям в использовании. ловить ошибки.
Теперь о Lazy multiExecutorLazy и Lazy multiExecutorLazyCopy . Dagger2 инициализирует соответствующий Executor только при первом вызове multiExecutorLazy.get () и multiExecutorLazyCopy.get () . Затем Dagger кэширует инициализированные значения для каждого Lazy <> и будет возвращать кешированные значения при последующих вызовах multiExecutorLazy.get () и multiExecutorLazyCopy.get () .
Таким образом, multiExecutor и multiExecutor2 относятся к одному объекту, а multiExecutor3 — ко второму.
Но если мы добавим аннотацию @Singleton к методу provideMultiThreadExecutor () в AppModule , то объект будет кэшироваться для всего дерева зависимостей, а multiExecutor , multiExecutor2 , multiExecutor3 будет тот же объект.
Будьте осторожны.
Мы подошли к очень нетривиальной задаче. Что, если мы хотим, чтобы построение графа зависимостей происходило в фоновом режиме? Звучит многообещающе? Да, я говорю о производителей .
Честно говоря, эта тема заслуживает отдельного рассмотрения. Там много особенностей и нюансов, уже опубликовано достаточно хороших материалов. Теперь я расскажу только о плюсах и минусах Producers .
Плюсы. Ну и самый главный плюс — это загрузка в фоновом режиме и возможность управлять этим процессом загрузки.
Минусы. Производители зависят от Guava, что означает плюс 15к методов к apk. Но хуже всего то, что использование Producers испортит общую архитектуру приложения и сделает код более запутанным. Если у вас уже был Кинжал, а затем вы решили перенести инициализацию объектов на задний план, это потребует дополнительных усилий.
В официальной документации есть специальный раздел, посвященный этой теме. Однако я бы очень рекомендовал статьи Мирослава Станека.У него очень хороший блог, и есть много статей о Dagger2. Я даже позаимствовал у него несколько картинок из прошлых статей.
Он пишет о производителях в этой статье.
А в следующей статье есть очень интересная альтернатива для загрузки дерева зависимостей в фоновом режиме, где на помощь приходит RxJava. Мне очень нравится его решение, так как оно полностью отрицает недостатки использования Producers при решении вопроса асинхронной загрузки.
Однако есть только один недостаток: Мирослав не совсем правильно применяет Observable.создать (…) . Но я написал об этом комментарий в статье, поэтому, пожалуйста, обратите на него внимание.
А теперь давайте посмотрим, как выглядит объектный код с областью видимости (с «правильным» RxJava):
Обратите внимание на @Singleton и интерфейс Lazy в AppModule . Lazy гарантирует, что тяжелый объект будет инициализирован во время запроса, а затем кэширован.
А что делать, если мы хотим каждый раз получать новую копию этого «тяжелого» объекта? Затем нам нужно изменить AppModule :
Для метода provideHeavyExternalLibrary () мы удалили область , а в provideHeavyExternalLibraryObservable (final Provider heavyExternalLibraryLazy) вместо Provider мы используем Provider вместо Provider. .В результате heavyExternalLibrary и heavyExternalLibraryCopy в MainActivity являются разными объектами.
Также есть возможность переместить весь процесс инициализации дерева зависимостей в фоновый режим. Вы хотите знать как? Очень просто. Сначала посмотрите, как это было (из статьи Мирослава):
А теперь посмотрите на обновленный метод void setupActivityComponent () (с моими правками на RxJava):
В последнем разделе мы говорили о производительности запуска приложения.Однако мы знаем, что если речь идет о производительности и скорости, нам нужно измерить! Не следует полагаться на интуицию и чувство «вроде бы быстрее». И Мирослав снова помогает нам в этой и этой статьях. Что бы мы делали без него, не представляю.
В Dagger появляются новые интересные функции, обещающие сделать нашу жизнь проще. Но понять, как все работает и что это дает, оказалось непростой задачей. Ну что ж, приступим!
Это интересная аннотация.Это экономит память, но фактически не ограничивается какой-либо областью , что делает очень удобным повторное использование зависимостей в любых компонентах. Т.е. это что-то среднее между областью действия и областью действия .
В документации есть очень важный момент, который почему-то изначально не бросается в глаза: « Для каждого компонента, который использует зависимость @Reusable, эта зависимость кэшируется отдельно. »И мое дополнение:« В отличие от аннотации области видимости, где объект кэшируется при создании, а его экземпляр используется дочерними и зависимыми компонентами. ”
Давайте сразу посмотрим на пример:
Наш главный компонент:
Компонент приложения имеет два подкомпонента . Вы заметили конструкцию FirstComponent.Builder ? Поговорим об этом позже.
Теперь давайте посмотрим на UtilsModule :
NumberUtils с аннотацией @Reusable , а StringUtils — без области действия .
Далее у нас есть два Subcomponens :
FirstComponent вводит только в MainActivity и SecondComponent вводит в SecondActivity и ThirdActivity .
Давайте посмотрим код:
Кратко о навигации. Из MainActivity мы попадаем в SecondActivity , а затем в ThirdActivity . А теперь вопрос. Когда мы уже на третьем экране, сколько будет создано объектов NumberUtils и StringUtil ?
Поскольку StringUtils не имеет области видимости, будут созданы три экземпляра, т.е. при каждой инъекции создается новый объект. Мы знаем это.
Но будет два объекта NumberUtils — один для FirstComponent , а другой для SecondComponent .И здесь я снова дам основное представление о @Reusable из документации: « Для каждого компонента, который использует зависимость @Reusable , эта зависимость кэшируется отдельно! ”. В отличие от аннотации области , где объект кэшируется при создании, а его экземпляр используется дочерним и зависимым компонентами .
Но сами гуглеры предупреждают, что если вам нужен уникальный изменяемый объект, используйте только аннотации с ограниченной областью видимости.
Я также дам вам ссылку на вопрос по SO о сравнении @Singleton и @ Reusable .
Функция, которая делает код более красивым. Раньше для создания @Subcomponent нам приходилось писать что-то вроде этого:
Мне не нравился этот подход, потому что родительский компонент был загружен с ненужными знаниями о модулях, которые используют дочерние подкомпоненты. К тому же передача большого количества аргументов выглядит не очень красиво, потому что для таких целей есть построитель шаблонов.Теперь это красота:
Теперь стало намного лучше =)
Теперь у нас есть возможность сделать что-то вроде этого:
То есть методы, отвечающие за предоставление зависимостей в модулях, можно сделать статическими. Сначала не совсем понял, зачем мне это вообще нужно? И оказывается, запрос на такую фичу существовал давно, и бывают ситуации, когда она пригодится.
В SOF был задан хороший вопрос по этой теме: «Чем на самом деле отличается @Singleton от @Provide static ?».Чтобы хорошо понять эту разницу, нужно прочитать ответ на вопрос, параллельно экспериментируя и глядя на сгенерированный код.
Предположим, что у нас есть три разные версии одного и того же метода в модуле:
В то же время authManager.currentUser () может предоставлять разные экземпляры в разное время.
Возникает закономерный вопрос: чем отличаются эти методы.
В первом случае у нас классический унскоп . Каждому запросу будет предоставлен новый экземпляр authManager.currentUser () (точнее, новая ссылка на currentUser).
Во втором случае ссылка на currentUser будет кэшироваться при первом запросе и будет выдаваться при каждом последующем запросе. То есть, если currentUser изменился в AuthManager , то будет дана старая ссылка на недопустимый экземпляр.
Третий случай более интересный. Поведение этого метода аналогично unscope , то есть для каждого запроса будет предоставлена новая ссылка.Это первое отличие от @Singleton , который кэширует объекты. Таким образом, размещение инициализации объекта в методе @Provide static не совсем уместно.
Тогда в чем разница между @Provide static и unscope ? Предположим, у нас есть следующий модуль:
AuthManager предоставляется другим модулем как Singleton . Теперь быстро просмотрите сгенерированный код по адресу AuthModule_CurrentUserFactory (в Android Studio просто поместите курсор на currentUser и нажмите Ctrl + B):
И если вы добавите статику к currentUser :
Тогда мы получим:
Обратите внимание, что в версии static нет AuthModule .Таким образом, статический метод вызывается компонентом напрямую, минуя модуль . А если в модуле есть только статические методы, то экземпляр модуля даже не создается.
Это оперативность и отсутствие лишних звонков. На самом деле здесь есть прирост производительности. Также известно, что вызов статического метода на 15–20% быстрее, чем нестатического аналога. Если я ошибаюсь, Александр Ефременков меня поправит. Он знает точно и при необходимости сделает соответствующие замеры.
Мега-удобное объединение, значительно сокращающее шаблонный код. Когда я только начинал изучать Dagger, я не понимал, зачем нужны инъекции конструкторов. Откуда берутся предметы? А потом был @Binds . Но на самом деле все довольно просто. Спасибо Владимиру Тагакову и этой статье за помощь.
Рассмотрим типичную ситуацию. Существует интерфейс Presenter и его реализация:
Мы предоставляем все внутри модуля и внедряем интерфейс Presenter в Activity:
Допустим, нашему FirstPresenter нужны вспомогательные классы, которым он делегирует часть работы.Для этого нам нужно создать еще два метода в модуле, которые будут предоставлять новые классы, затем изменить конструктор FirstPresenter и, следовательно, обновить соответствующий метод в модуле.
Модуль будет иметь следующий вид:
И то же самое происходит каждый раз, когда вы хотите добавить одни классы и поделиться ими с другими. Модуль очень быстро загрязняется. К тому же кода слишком много, не так ли? Но есть решение, которое значительно сокращает код.
Прежде всего, если нам нужно создать зависимость и предоставить готовый класс, а не интерфейс ( HelperClass1 и HelperClass2 ), мы можем использовать инъекцию конструктора.Это будет выглядеть так:
Обратите внимание, что к классам добавлена аннотация @FirstScope , чтобы Dagger понимал, какому дереву зависимостей назначить эти классы.
Теперь мы можем безопасно удалить провайдеров HelperClass1 и HelperClass2 из модуля:
Как еще мы можем уменьшить код в модуле? Здесь мы применяем @Binds :
И добавляем инъекцию конструктора внутри FirstPresenter :
Что здесь нового? FirstModule и provideFirstPresenter стали абстрактными.Аннотация @Provide заменена на @Binds . И мы передаем аргументам не необходимые зависимости, а конкретную реализацию !
Scope аннотация была добавлена в FirstPresenter — @FirstScope , с помощью которой Dagger понимает, где разместить этот класс. Также в конструктор добавлена аннотация @Inject . Он стал намного чище, и теперь намного проще добавлять новые зависимости!
Несколько ценных дополнений к абстрактным модулям от Андрея Заяца.
Давайте вспомним, что FirstModule относится к FirstComponent , который, в свою очередь, является подкомпонентом AppComponent . И чтобы создать FirstComponent , мы сделали это:
Но как нам создать экземпляр FirstModule , если он абстрактный? В предыдущих статьях я упоминал, что если мы ничего не передаем конструктору модуля (т.е. используем конструкторы по умолчанию), то мы можем опустить инициализацию этих модулей при создании компонента:
И Dagger сам решает, что делать с абстрактными и не -абстрактные модули и способы обеспечения всех этих необходимых зависимостей.
Также обратите внимание, что если модуль имеет только абстрактные методы, то он может быть реализован через интерфейс:
Кроме того, мы можем добавлять только статические методы к абстрактным модулям, но не «нормальные»:
Далее я предоставим вам список возможностей с краткими описаниями и ссылками на качественные ресурсы:
- Muitibindings . Позволяет связать объекты в коллекции (Set и Map). Подходит для реализации «архитектуры плагинов». Я очень рекомендую эту очень подробную статью новичкам.Более интересные примеры применения Multibinding можно найти в статьях Мирослава здесь и здесь. И ссылка на официальную документацию дополнительно.
- Повторяемые ссылки полезны, когда у вас есть проблемы с нехваткой памяти. С помощью соответствующих аннотаций мы отмечаем объекты, которыми можно пожертвовать в случае дефицита памяти. Это можно рассматривать как взлом.
В документации ( Releasable References подраздел) все достаточно четко описано, как ни странно. - Тестирование . Конечно, для Unit-тестирования Dagger не нужен. Но для функциональных, интеграционных и пользовательских тестов может быть полезно заменить определенные модули. Артем Зиннатуллин очень хорошо объясняет тему в своей статье и на примере. Раздел о тестировании выделен в документации. Но опять же, Google не может правильно описать, как заменить компонент. Как правильно создавать макеты модулей и заменять их. Для замены компонента (отдельных модулей) я использую способ Артема.Да, было бы здорово, если бы можно было создавать тестовые компоненты и модули в отдельных классах и красиво включать их все в файл тестового приложения. Может кто знает?
- @BindsOptionalOf . Работает с Optional из Java 8 или Guava, что делает эту функцию труднодоступной для нас. Если интересно, вы можете найти описание в конце документации.
- @BindsInstance . Его главное сообщение — прекратить передачу любых объектов через конструктор модуля.Очень распространенный пример — когда глобальный контекст передается через конструктор AppComponent. Таким образом, с этой аннотацией вам не нужно этого делать. В конце документации есть пример.
Вот и все! Вроде все моменты были покрыты. Если чего-то не хватает или недостаточно описано, напишите мне! Исправлю это.
Авторы:
Евгений Мацюк
Роман Яцина
Атабек Муртазаев
.
HomepageActivity
в пакете ui.homepage
. presenter
со следующими изменениями: @Inject
presenter
будет выглядеть так: @Inject
не является частью Dagger; он принадлежит к аннотациям javax . @Inject
сообщает Dagger, что вы хотите, чтобы он сделал инъекцию поля presenter . onCreate ()
, добавив вызов AppComponent.inject ()
следующим образом: AppComponent
из WikiApplication
и просите его внедрить все известные зависимости в HomepageActivity
. Поскольку вы аннотировали ведущего
с помощью @Inject
, Dagger внедрит конкретный объект HomepagePresenter
в HomepageActivity
. provideHomepagePresenter ()
в классе PresenterModule
, и использует его для создания внедренного объекта HomepagePresenter
. HomepageActivity
: inject ()
в AppComponent
с аргументом HomepageActivity
. provideHomepagePresenter ()
в PresenterModule
. @Inject
к домашней странице Презентатор
на домашней странице Активность
. WikiApplication.wikiComponent.inject (this)
в onCreate ()
в HomepageActivity
. HomepageActivity
как целевой класс и HomepagePresenter
как исходный интерфейс, который нужно внедрить, то вышеуказанные шаги можно обобщить следующим образом для любого целевого класса, требующего внедрения исходных интерфейсов: inject ()
в AppComponent
с аргументом класса Target
. @Provides
в PresenterModule
для каждого исходного объекта, который нужно внедрить. @Inject
к каждой переменной-члену Source
в классе Target
. WikiApplication.wikiComponent.inject (this)
в onCreate ()
в Target
class. EntryPresenter
в SearchActivity
.Это будет включать удаление следующей строки кода: HomepageActivity
. Используйте шаблон, и если вы застряли, ознакомьтесь с окончательным кодом проекта в конце этого руководства. dagger
, на этот раз с именем NetworkModule
, который начинается следующим образом: WikiApi
в реализации презентатора приложения, чтобы презентаторы могли вызывать API. HomepagePresenterImpl
, вы увидите, что WikiApi
зависит от объекта OkHttpClient
, и если вам нужна сложная настройка для HTTP-клиента, вам нужно будет настраивать OkHttpClient
каждые время (например, если вы хотите включить ведение журнала с помощью LoggingInterceptor
). WikiApi
требует 3 строки, которые представляют: NetworkModule
вместе с постоянной строкой: @Named
, которая, опять же, не является частью Dagger, но предоставляется javax . String
, и, поскольку String
является наиболее распространенным типом для использования в приложении для Android, вы воспользовались аннотацией @Named
, чтобы указать конкретную строку, которая должна быть предоставлена. Этот же метод можно использовать для ваших собственных типов, если вам нужно ввести несколько вариантов. String
, представляющая базовый URL, добавьте следующее в конец NetworkModule
: WikiApi
. dagger
с именем WikiModule и добавьте методы предоставления для API: OkHttpClient
, HttpUrl.Builder
объект и WikiApi
объект. Затем в WikiModule вы добавили методы для объектов Homepage
и Wiki
, запрашивая зависимости от предыдущих методов. Wiki
, Dagger сначала предоставит WikiApi
, а затем OkHttpClient
и HttpUrl.Builder . начиная с provideWiki (api: WikiApi)
. baseUrl
для provideRequestBuilder (@Named (NAME_BASE_URL) baseUrl: String)
. @Singleton
будет создан только один экземпляр объектов WikiApi
и OkHttpClient
, который будет использоваться обоими действиями в приложении. NetworkModule
и WikiModule
в AppComponent
, обновив аннотацию @Component
до следующего: PresenterModule
, чтобы Context
передавался в качестве аргумента конструктора: HomepagePresenterImpl
и EntryPresenterImpl
: Домашняя страница / Wiki
конструкторам требуется параметр WikiApi
, но нам больше не нужно его предоставлять, так как Dagger внедрит его, поскольку он присутствует на его графике. На этом этапе вы можете удалить инициализацию: WikiApi
в докладчиков.Это позволило удалить дублированное создание объектов OkHttpClient
и WikiApi
. WikiApi
требуется конструктор с введенным параметром, поэтому вы должны его обновить: HttpUrl.Builder
каждый раз больше, поэтому вы можете обновлять методы getHomepage () / search (query: String)
:В этой третьей части мы рассмотрим различные интересные и важные функции библиотеки, которые могут вам понадобиться в будущем.
Он пишет о производителях в этой статье.
Давайте посмотрим код:
Возникает закономерный вопрос: чем отличаются эти методы.
Scope аннотация была добавлена в FirstPresenter — @FirstScope , с помощью которой Dagger понимает, где разместить этот класс. Также в конструктор добавлена аннотация @Inject . Он стал намного чище, и теперь намного проще добавлять новые зависимости!
Давайте вспомним, что FirstModule относится к FirstComponent , который, в свою очередь, является подкомпонентом AppComponent . И чтобы создать FirstComponent , мы сделали это:
В документации ( Releasable References подраздел) все достаточно четко описано, как ни странно.
Евгений Мацюк
Роман Яцина
Атабек Муртазаев