Могу ли я просто ввести супер класс при использовании dagger2 для инъекции зависимостей?
Я использую Dagger2 для DI в своем приложении для android. Я обнаружил, что мне нужно написать метод inject для каждого класса, который использует поле @Inject. Есть ли способ, которым я могу просто ввести родительский класс, чтобы мне не нужно было вызывать inject для каждого подкласса?
Возьмем, к примеру, активность. У меня есть BaseActivity
то, что каждая деятельность простирается от. Есть ли способ, которым я могу просто создать метод inject в компоненте для BaseActivity и просто вызвать inject в onCreate BaseActivity и @ inject поля в sub деятельность вводится автоматически?
3 ответов
это невозможно сделать прямо сейчас. Объяснение Григория пинка:
вот как работают методы инъекций членов:
- вы можете сделать метод инъекции элементов для любого типа, который имеет
@Inject
в любом месте иерархии классов. Если это не так, вы получите ошибка.- все
@Inject
будут введены члены ed во всей иерархии типов: тип аргумента и все супертайпы.- нет членов будет
@Inject
ed для подтипы типа аргумента.
этот вопрос обсуждался здесь и здесь, следите за обновлениями. Но вряд ли это изменится в ближайшее время, потому что Dagger 2-это близко к выпуску.
я столкнулся с такой же ситуацией. Один из способов немного облегчить инъекцию от общего компонента во всех действиях заключается в следующем:
1) расширьте класс приложения, чтобы иметь возможность создавать общий компонент и сохранять ссылку на него.
public class ApplicationDagger extends Application {
private ApplicationComponent component;
@Override
public void onCreate(){
super.onCreate();
component = DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();
}
public ApplicationComponent getComponent(){
return component;
}
}
2) Создайте абстрактный DaggerActivity, который получает общий компонент из приложения и вызывает абстрактный метод injectActivity
, давая компонент в качестве аргумента. Вот так:
public abstract class DaggerActivity extends Activity {
@Override
public void onCreate(Bundle saved){
super.onCreate(saved);
ApplicationComponent component = ((ApplicationDagger) getApplication()).getComponent();
injectActivity(component);
}
public abstract void injectActivity(ApplicationComponent component);
}
3) Наконец, вы должны фактически ввести each Activity
расширения DaggerActivity
. Но теперь это можно сделать с меньшими усилиями, так как вам нужно реализовать abstract
способ в противном случае вы получите ошибки компиляции. Здесь мы идем:
public class FirstActivity extends DaggerActivity {
@Inject
ClassToInject object;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//initialize your Activity
}
@Override
public void injectActivity(ApplicationComponent component) {
component.inject(this);
}
}
конечно, вы все равно должны объявить каждое действие явно в вашем компоненте.
UPDATE: инъекция объектов @ActivityScope во фрагменты
в какой-то момент, мне нужно использовать настраиваемые области to привязка объектов к
Activity
жизненный цикл. Я решил расширить этот пост, так как это может помочь некоторым людям.
допустим, у вас есть @Module класс ActivityModule
и @Subcomponent интерфейс ActivityComponent
.
вам нужно будет изменить DaggerActivity
. The Activities
расширения DaggerActivity
необходимо будет реализовать новый метод (изменение подписи).
public abstract class ActivityDagger extends AppCompatActivity {
ActivityComponent component;
@Override
protected void onCreate(Bundle savedInstanceState) {
component = ((ApplicationDagger) getApplication()).getComponent().plus(new ActivityModule(this));
injectActivity(component);
super.onCreate(savedInstanceState);
}
ActivityComponent getComponent() {
return component;
}
public abstract void injectActivity(ActivityComponent component);
}
тогда класс FragmentDagger
расширения Fragment
можно создать такой :
public abstract class FragmentDagger extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityDagger activityDagger = (ActivityDagger) getActivity();
ActivityComponent component = activityDagger.getComponent();
injectFragment(component);
}
public abstract void injectFragment(ActivityComponent component);
}
что касается Activities
, the Fragments
расширения FragmentDagger
есть только один способ реализации:
public abstract void injectFragment(ActivityComponent component);
вы должны иметь возможность повторно использовать Fragments
куда хочешь. Обратите внимание, что
метод super.onCreated()
на ActivityDagger
должен вызываться после создания экземпляра компонента. В противном случае, вы получите NullPointerException когда Activity
состояние воссоздается, потому что метод super.onCreate()
на Fragment
будет называться.
вы можете сделать немного взломать, используя отражение:
public class UiInjector {
private static final String METHOD_NAME = "inject";
private final UIComponent component;
public UiInjector(final UIComponent component) {
this.component = component;
}
public void inject(final Object subject) {
try {
component.getClass()
.getMethod(METHOD_NAME, subject.getClass())
.invoke(component, subject);
} catch (final NoSuchMethodException exception) {
throwNoInjectMethodForType(component, subject.getClass());
} catch (final Exception exception) {
throwUnknownInjectionError(exception);
}
}
private void throwNoInjectMethodForType(final Object component, final Class subjectType) {
throw new RuntimeException(component.getClass().getSimpleName() +
" doesn't have inject method with parameter type : " + subjectType);
}
private void throwUnknownInjectionError(final Exception cause) {
throw new RuntimeException("Unknown injection error", cause);
}
}
в этом случае вам все равно нужно написать метод inject в компоненте, но вам не нужен метод inject в каждом действии, фрагменте, представлении, что угодно.
почему это работает? когда мы используем getClass()
на предмет инъекции получит класс потомка, а не базовый.
осторожно! Если вы используете Proguard, вам нужно добавить next
-keep class <ComponentClass> { *; }
к вашим правилам держать впрыснуть методы как в компоненте