Вложенные / рекурсивные инъекции с кинжалом

При использовании кинжала, какие подходы позволят свободно / просто создавать экземпляры @Inject для объектов, которые также создаются путем инжекции.

Например, приведенный ниже код вводит объект типа Bar в заданный объект Foo. Он будет делать это одним из двух способов отображения. Однако Sly-поле каждого объекта Bar не соответствует этому поведению.

Foo

public class Foo { @Inject Bar bar; public String getValue() { return "Foo's bar value: " + bar.getValue(); } } 

бах

 public class Bar { @Inject Sly sly; public String getValue() { return "Bar's sly value: " + sly.getValue(); } } 

лукавый

 public class Sly { public String getValue() { return "Hey!"; } } 

модуль

 @Module( injects = { Foo.class, Bar.class } ) public class ExampleTestModule { @Provides Bar provideBar() { return new Bar(); } @Provides Sly provideSly() { return new Sly(); } } 

тесты

 public void testWorksWithInject() { Foo foo = new Foo(); ObjectGraph.create(new ExampleTestModule()).inject(foo); assertEquals("...", foo.getValue()); // NullPointerException } public void testWorksWithGet() { Foo foo = ObjectGraph.create(new ExampleTestModule()).get(Foo.class); assertEquals("...", foo.getValue()); // NullPointerException } 

В любом случае, Bar's Sly не создается / @ Injected. Конечно, Кинжал допускает инъекцию конструктора, которая решает проблему. Я хотел бы знать, есть ли альтернативы переустановке этих классов в список параметров конструкторов. Что хорошо работает для вас?

Таким образом, проблема здесь в том, что на баре есть @Inject Sly, но затем вы предоставляете Bar в методе @Provides. @Provides методы переопределяют поведение экземпляров по умолчанию, поэтому вы говорите Кинжалу о создании «нового бара ()» и возвращаете его как выполнение положения Бар.

Самое простое, что вы можете сделать, это просто удалить метод enableBar (), поскольку он не нужен. Если конкретный тип имеет конструктор @Inject или поле @Inject, Dagger будет вводить свои зависимости и создавать его, если только он не имеет недоступного конструктора или конструктора с параметрами, который не имеет @Inject. Но ваш случай выше класса Bar {} выше полностью подходит для неявного связывания без использования методов @Provides.

Если по какой-то причине вам нужно изменить поведение по умолчанию, вы все равно можете создать его в методе @Provides, но вы должны вручную передать введенное значение. Однако методы @Provides могут сами вводиться путем добавления параметров к самому методу @Provides. Таким образом, вы могли бы это сделать.

 @Provides Bar provideBar(Sly sly) { Bar bar = new Bar(); bar.sly = sly; return bar; } 

Метод @Provides берет на себя всю ответственность за надлежащее предоставление экземпляра, включая новизну, назначения, любую логику инициализации и т. Д.

Но, учитывая ваш пример выше, простое решение состоит в том, чтобы просто удалить enableBar () из вашего модуля и позволить Dagger автоматически инициализировать Bar.

Существуют различные альтернативы, которые Dagger 2, по-видимому, предпочитает вложенную инъекцию: попросите компонент, MemberInjector или дайте Bar аннотированный конструктор @Inject.

Если Bar имеет @Inject аннотированный конструктор, то вы можете достичь полной неизменности:

 class Bar { private final Sly sly; @Inject public Bar(Sly sly) { this.sly = sly; } } 

Другой альтернативой, когда вы только частично вводите членов, является использование метода @Provides с элементом MemberInjector или компонентом (MembersTestComponent?) В качестве аргумента метода:

 @Provides Bar provideBar(MembersInjector<Bar> injector) { Bar bar = new Bar(); injector.inject(bar); return bar; } 

Предоставление аргумента MembersTestComponent, к сожалению, приведет модуль обратно к вашему компоненту и сделает решение менее связным. Предоставление MembersInjector особенно полезно, если Bar содержит облачные значения, предоставленные Компонентом (например, пользователь внутри Tweeter в разговоре Devoxx 2014 от Jake Wharton).

Intereting Posts
Как правильно и последовательно имитировать местоположение в Android? Поддержка PAC отключена, поскольку нет реализации системы Android Studio: Theme.Sherlock.Light.DarkActionBar не может быть разрешен Оттенок для Android ImageView События, которые не запускаются в Google Analytics через Диспетчер тегов Google Мобильное приложение – Ориентация на iPhone, WP7, Android и Blackberry Внедрение трансформатора страницы с уменьшением масштаба Android для ViewFlipper Как изменить фон названия Android Alert Dialog Отображать пользовательскую информацию на экране блокировки. В Android Как проверить, что строка является действительным шестнадцатеричным цветовым кодом в android После импорта Android Project в Eclipse, иконки пакета являются «белыми» Ошибка в Android "SuperNotCalledException: активность не вызывала super.OnCreate ()" Нажмите внешний редактор, чтобы потерять фокус Snackbar.setCallback () не может быть разрешен в Android AppCompat Получение растрового изображения из пользовательского SurfaceView