Внедрение зависимостей CustomView с кинжалом 2 (в пределах действия)

Мой вопрос подобен этому .

Так, например, у меня есть реализация LiveData :

 public class CustomLiveData extends LiveData<SomeEvent> { @Inject public CustomLiveData(@ActivityContext Context context) { //.... } } 

Что я хочу ввести в пользовательский вид:

 public class CustomView extends View { @Inject SomeApplicationProvider anyProvider; @Inject CustomLiveData dataProvider; // Getting @com.di.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method. // @com.di.qualifiers.ActivityContext android.content.Context is injected at com.repositories.CustomLiveData.<init>(context) // com.repositories.CustomLiveData is injected at com.ui.CustomView.dataProvider com.ui.CustomView is injected at // com.di.ApplicationComponent.inject(view) public CustomView(Context context) { this(context, null); } public CustomView(Context AttributeSet attrs) { super(context, attrs); // Works ok for application provider Application.getComponent(context).inject(this); } } 

И вот остальные классы DI:

 @ApplicationScope @Component( modules = {AndroidInjectionModule.class, ActivityBuilder.class }) public interface ApplicationComponent extends AndroidInjector<MyApp> { void inject(MyApp application); void inject(CustomView view); @Component.Builder abstract class Builder extends AndroidInjector.Builder<MyApp> { public abstract ApplicationComponent build(); } } @ActivityScope @Module (subcomponents = MainActivitySubcomponent.class) public abstract class ActivityBuilder { @Binds @IntoMap @ActivityKey(MainActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindActivityInjectorFactory(MainActivitySubcomponent.Builder builder); //... } @Subcomponent(modules = {MainActivityModule.class}) public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<MainActivity> { } } @ActivityScope @Module public class MainActivityModule { @Provides @ActivityContext public Context provideActivityContext(MainActivity activity) { return activity; } // Seems to be wrong or not enough!? @Provides public CustomLiveData provideCustomLiveData(@ActivityContext Context context) { return new CustomLiveData(context); } } @Qualifier public @interface ActivityContext{ } 

Обратите внимание, что я не получаю жалобы компилятора, если CustomLiveData вводится в MainActivity вместо этого в представление. Благодаря!

Tl; dr Не вводить зависимости уровня модели внутри пользовательских объектов View

Подклассы View не являются хорошими мишенями для инъекции кинжала 2. Объекты View предназначены для рисования, а не для других, поэтому имя «вид». Конструкторы для View должны ясно это сделать; Они предназначены для раздувания объектов View из атрибутов, указанных в XML. Другими словами, объект View должен быть указан в файле layout.xml , завышенном в соответствующей точке жизненного цикла, а затем получен с использованием findViewById(int id) , Butterknife или привязки данных. Таким образом, лучшие пользовательские объекты View не имеют никаких зависимостей.

Если вы хотите связать View и некоторые данные с уровня модели, стандартным шаблоном является написать адаптер, такой как RecyclerView и ListView . Если это невозможно, использование установщика (например, setData() ) предпочтительнее передавать зависимости из слоя модели в конструкторе или запрашивать инъекцию из одного из методов жизненного цикла View .

Если вместо этого вы LiveData свой объект LiveData внутри Activity или Fragment с AndroidInjector класса AndroidInjector то правильный Context будет предоставлен без необходимости делать что-либо. Это объясняет ваш комментарий: «Я не получаю жалобы компилятора, если CustomLiveData вводится в MainActivity вместо этого в представление».

После того, как вы ввели объект LiveData в Activity, используйте один из вышеуказанных методов (адаптер или сеттер), чтобы связать данные с вашим пользовательским View . См. Пример Google Android Architecture, где элементы с уровня модели вводятся с помощью Dagger 2, а затем связаны с ListView с помощью findViewById и setAdapter()

Ссылка на проблему с кинжалом 2, в которой обсуждается инжекция объектов View :

https://github.com/google/dagger/issues/720

Иерархия вашего кинжала выглядит так: appcomponent -> activitycomponent

Вы пытаетесь ввести context активности внутри представления, который напрямую зависит от appcomponent .

Это невозможно, поскольку нет способа, который мог бы обеспечить контекст активности в appcomponent . Вместо этого внутри представления вы должны получить активность (например, с помощью getContext ), извлечь из нее getContext activitycomponent и только затем ввести CustomLiveData .

Intereting Posts
Привязать индивидуальный вид андроида к определенному макету xml (возможно ли это?) Как создавать приложения в android, которые нельзя удалить? Можем ли мы сделать системные приложения? Исходный код для Android Как отслеживать push-уведомления FCM отправлять серверную страницу формы или Rest Client? Android получает разницу в миллисекундах между двумя датами Android java.lang.IllegalArgumentException: no char field 'exponential' в android 2.3 Получить имя файла за дружественным URL в Java @VisibleForTesting работает не так, как ожидалось С помощью библиотеки поддержки v7 эта ошибка: Тип android.support.v4.app.TaskStackBuilder $ SupportParentable Приемник изменения связи получает ложные намерения в android Кроссплатформенный обмен кодами iPhone / Android Android-приложение, совместимое с 0 устройствами Как предоставить возможность выбора Wi-Fi или GPRS для подключения к сети в приложении для Android Создание без знака, выпуск apk с Android Studio Как изменить высоту кнопки «Войти в систему с помощью Facebook»?