Подтвердить что ты не робот

Кинжалы 2 Конструкторы для инъекций

Я начинаю использовать Dagger 2 в приложении, которое я разрабатываю, но у меня есть некоторые вопросы о том, как работает Dagger 2.

Я получаю всю логику методов @Provides и аннотацию @Inject для инициализации ваших зависимостей, но аннотация @Inject для конструкторов классов - вот некоторые ошибки.

Например:

Мне мое приложение, у меня есть один модуль, определенный ContextModule, для извлечения контекста моего приложения:

ContextModule.java

@Module
public class ContextModule {

    private final Context context;

    public ContextModule(Context context) {
        this.context = context;
    }

    @Provides
    public Context context() {
        return this.context;
    }
}

Этот модуль используется моим BaseActivityComponent:

BaseActivityComponent.java

@BaseActivityScope
@Component(modules = ContextModule.class)
public interface BaseActivityComponent {
    void injectBaseActivity(BaseActivity baseActivity);
}

До сих пор так хорошо.. тогда у меня есть класс AuthController, который зависит от контекста, и я хочу вставить его в свой BaseActivity. Итак, в моем AuthControllers.class у меня есть что-то вроде:

public class AuthController {

    private Context context;

    @Inject
    public AuthController(Context context) {
        this.context = context;
    }

    public void auth() {
        // DO STUFF WITH CONTEXT
    }
}

И я добавляю его в свой BaseActivity, например:

public class BaseActivity extends AppCompatActivity {

    @Inject
    AuthController authController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        BaseActivityComponent component = DaggerBaseActivityComponent.builder()
            .contextModule(new ContextModule(this))
            .build();

        component.injectBaseActivity(this);

        authController.auth();

    }
}

Теперь мой вопрос: как кинжал знает, что мои AuthControllers являются зависимыми для BaseActivity? Просто объявив

@Inject
AuthController authController;

он похож на то же, что если бы я создал ControllerModule, например:

@Module(includes = ContextModule.class)
public class ControllerModule {

    @Provides
    AuthController authController(Context context) {
        return new AuthController(context);
    }

}

И затем в моем BaseActivityComponent я бы добавил мой AuthController getter и изменил свой модуль зависимостей на ControllersModule:

@BaseActivityScope
@Component(modules = ControllersModule.class)
public interface BaseActivityComponent {

    void injectBaseActivity(BaseActivity baseActivity);

    AuthController getAuthController();
}

Когда я вызываю injectionBaseActivity (это), он "сообщает" кинжалу, что все аннотации @Inject являются зависимостями моего класса, а затем он ищет мой проект для аннотированных конструкторов @Inject, которые соответствуют этому типу?

Я подумал, что хорошая вещь о Dagger 2 заключается в том, что файлы модуля могут использоваться как "документация" моих зависимостей три. Но если просто добавить @Inject во все конструкторы, которыми я управляю, не мог бы он немного запутать в будущем, так как вы не знаете, что на самом деле зависит от чего? (Я имею в виду, вы знаете, что зависит от того, что вам нужно просто просмотреть много файлов, чтобы действительно узнать)

Есть ли какие-либо рекомендации по использованию @Inject-аннотаций в конструкторах или когда добавлять метод @Provides в файлы модулей? Я получаю это, используя @Inject в конструкторе. Мне не нужно изменять определение конструктора в моем файле модуля, но есть ли недостаток?

Спасибо.

4b9b3361

Ответ 1

Когда я вызываю injectionBaseActivity (это), он "сообщает" кинжалу, что все аннотации @Inject являются зависимостями моего класса, а затем он ищет мой проект для аннотированных конструкторов @Inject, которые соответствуют этому типу?

Совершенно верно. Но это не делается, когда вы вызываете injectBaseActivity, но все это происходит во время компиляции. Это один из способов обработки обработки аннотаций (другой использует отражение во время выполнения).

Когда вы создаете свой проект, вы можете включить обработчик кинопленки-аннотации, который вы включаете (как зависимость) в свой файл build.gradle, со списком всех ваших полей, классов и т.д., аннотированных аннотацией @Inject, и строит граф зависимости с ним. Затем он решает график, генерируя исходный код, который предоставляет все зависимости для элементов на графике.

injectBaseActivity просто выполняет код, который был сгенерирован ранее, и назначает все зависимости вашему объекту. Это правильный исходный код, который вы можете читать и отлаживать.

Причина, по которой это шаг компиляции, просто put — - это производительность и валидация. (например, если у вас есть некоторый цикл зависимостей, вы получаете ошибку компиляции)


как кинжал знает, что мои AuthControllers являются зависимыми для BaseActivity?

@Inject
AuthController authController;

Аннотируя поле @Inject, кинжал знает, что вы хотите AuthController. Все идет нормально. Теперь кинжал будет искать некоторые средства для обеспечения контроллера, поиска его в компоненте, зависимостях компонентов и модулях компонентов. Он также посмотрит, может ли класс быть поставлен сам по себе, потому что он знает о его конструкторе.

Как кинжал знает о конструкторе объектов, если вы не включаете его в какой-либо модуль?

@Inject
public AuthController(Context context) { /**/ }

Аннотируя конструктор с инъекцией, вы также сказали кинжалу, что есть класс под названием AuthController, и вам нужен контекст для его создания. Это в основном то же самое, что добавлять его в ваш модуль.

Метод @Provides должен использоваться, если у вас нет исходного кода, чтобы просто добавить аннотацию @Inject к конструктору или если объект нуждается в дальнейшей инициализации. Или в вашем случае...

[...] файлы модуля могут использоваться как "документация" моего дерева зависимостей [...]

Да, конечно, вы могли бы это сделать. Но по мере роста вашего проекта вам придется поддерживать много ненужного кода, так как это можно было бы сделать с помощью простой аннотации к конструктору.

Есть ли какие-либо рекомендации по использованию @Inject-аннотаций в конструкторах или при добавлении метода @Provides в файлы модулей?

Если вы хотите предоставить разные версии для другого контекста (например, для реализации интерфейса двумя разными способами), также существует аннотация @Binds, которая сообщает кинжалу, какой класс вы хотите предоставить как реализацию.

Кроме того, я считаю, что вы всегда должны использовать инъекцию конструктора, когда это возможно. Если что-то изменится, вам не нужно прикасаться к каким-либо другим частям вашего кода, и это всего лишь код, который вы пишете, и, следовательно, меньше мест, где вы могли бы включить ошибку.

Также Dagger может и очень много оптимизирует, зная больше, и если вы реализуете ненужный код, ему придется работать с накладными расходами, которые вы ввели


Конечно, в конечном итоге все зависит от того, что вы считаете лучшим. В конце концов, это вы должны работать с вашим кодом;)