Проблема с инъекцией Kotlin + Dagger в зависимости от Android версии Android / SDK (?)

На прошлой неделе, при внедрении Dagger в моем текущем проекте MVP Kotlin, я тестировал его на старом телефоне с KitKat 4.4.2 (да, он все еще поддерживает все основные материальные возможности и прочее :)) из-за обслуживания основного телефона. Таким образом, на той неделе у меня были типичные проблемы, а не что-то необычное и исправлялось их более или менее быстро, исследуя предоставленные ошибки. Наконец, скомпилированный код, текущая версия проекта была построена без проблем и запускалась без серьезных ошибок в KitKat с взаимодействием с пользовательским интерфейсом.

Но когда я взял главный телефон с Nougat 7.1.2 из ремонтного центра и запустил приложение, я застрял в странной проблеме, связанной с DI. Сразу после этого я также запустил приложение на Marshmallow 6.0 и поймал еще один, точно такой же. Проблема кратко описана следующим образом:

И теперь самая смешная часть, которая сводит меня с ума: все доступные классы, которые не приносят никаких проблем, вводятся через инъекцию конструктора.

Но экземпляр Presenter, который вводится с помощью инъекции поля , при необходимости не инициализируется .

Разумеется, я старался не использовать модификатор lateinit и вводить его как поле с нулевым значением с помощью @JvmField или без него: результат тот же – он вообще не вводится.

Поскольку проблема связана с Activity , у меня есть «естественное ограничение», чтобы не использовать первичный конструктор для инъекций.

Вот исключение, которое не очень информативно для меня, кроме первой строки:

 kotlin.UninitializedPropertyAccessException: lateinit property presenter has not been initialized at .ui.common.view.BaseViewActivity.getPresenter(BaseViewActivity.kt:14) at .ui.main.view.MainActivity.onPlaceTypeClick(MainActivity.kt:143) at .ui.types.nearby.view.NearbyPlaceTypeItemViewHolder$bind$1.onClick(NearbyPlaceTypeItemViewHolder.kt:32) at android.view.View.performClick(View.java:5647) at android.view.View$PerformClick.run(View.java:22462) at android.os.Handler.handleCallback(Handler.java:754) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:163) at android.app.ActivityThread.main(ActivityThread.java:6205) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794) 

Вот какой код:

Приложение:

 class MyApp : MultiDexApplication(), HasActivityInjector { @Inject @JvmField var activityInjector: DispatchingAndroidInjector<Activity>? = null override fun onCreate() { super.onCreate() DaggerMyAppComponent.builder().create(this).inject(this) } override fun activityInjector(): AndroidInjector<Activity>? { return activityInjector } } 

AppComponent:

 @Singleton @Component(modules = [ MyAppModule::class, DataModule::class, PreferencesModule::class, ServiceModule::class, NavigationModule::class ]) interface MyAppComponent : AndroidInjector<MyApp> { @Component.Builder abstract class Builder : AndroidInjector.Builder<MyApp>() } 

AppModule:

 @Module(includes = [AndroidSupportInjectionModule::class]) abstract class MyAppModule { @Binds @Singleton abstract fun application(myApp: MyApp): Application @PerActivity @ContributesAndroidInjector(modules = [(MainActivityModule::class)]) abstract fun mainActivityInjector(): MainActivity //... other activity injectors } 

BaseActivityModule:

 @Module abstract class BaseActivityModule { @Binds @PerActivity internal abstract fun activity(appCompatActivity: AppCompatActivity): Activity @Binds @PerActivity internal abstract fun activityContext(activity: Activity): Context @Module companion object { const val ACTIVITY_FRAGMENT_MANAGER = "BaseActivityModule.activityFragmentManager" @JvmStatic @Provides @Named(ACTIVITY_FRAGMENT_MANAGER) @PerActivity fun activityFragmentManager(activity: AppCompatActivity): FragmentManager { return activity.supportFragmentManager } } } 

В настоящий момент у меня есть своего рода широкорасширяющаяся MVP-модель, поэтому каждый элемент / фрагмент имеет 1 View Module и 1 Presenter Module, а все обычные инъекции взаимодействуют через базовые классы. Вот пример частей деятельности DI :

 @Module(includes = [ BaseActivityModule::class, MainPresenterModule::class ]) abstract class MainActivityModule { @Binds @PerActivity abstract fun mainView(mainActivity: MainActivity): MainView @Binds @PerActivity abstract fun appCompatActivity(mainActivity: MainActivity): AppCompatActivity @PerFragment @ContributesAndroidInjector(modules = [LocationFragmentModule::class]) abstract fun locationFragmentInjector(): LocationFragment //... other related fragments injection methods } @Module abstract class MainPresenterModule { @Binds @PerActivity abstract fun mainPresenter(mainPresenterImpl: MainPresenterImpl): MainPresenter } 

BaseActivity:

 abstract class BaseActivity : AppCompatActivity(), HasSupportFragmentInjector { @Inject @field:Named(BaseActivityModule.ACTIVITY_FRAGMENT_MANAGER) lateinit var fragmentManager: FragmentManager @Inject lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment> override fun onCreate(@Nullable savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) } override fun supportFragmentInjector(): AndroidInjector<Fragment>? { return fragmentInjector } } 

Пример использования инъекции конструктора – MainPresenter (все операции с инъекциями – здесь нет проблем):

 @PerActivity class MainPresenterImpl @Inject constructor( val navigationManager: NavigationManager, val locationManager: LocationManagerImpl, val sharedPrefsRepo: SharedPreferencesRepository, view: MainActivity) : BaseViewPresenter<MainView>(view), MainPresenter { } 

И ниже – место, где начинается вся «магия»var presenter не инициализируется ни при каких обстоятельствах.

 abstract class BaseViewActivity<T : MVPresenter> (): BaseActivity(), MVPView { @Inject lateinit var presenter: T } 

НО, как сказано, это НЕ происходит в KitKat – приложение работает без проблем. Итак, еще раз: я предполагаю, что проблема существует, когда приложение работает на Marshmallow + (к сожалению, пока не известно о Lollipop).

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

Не может ли это быть связано с разрешением? Единственное опасное разрешение, которое у меня есть, – это местоположение устройства, и оно было проведено и протестировано.

В конце концов, если есть проблема с поддержкой / версией, с каким другим аспектом это могло бы быть связано?

Заранее спасибо.

UPD:

Кажется, что экземпляр презентатора привязан к Activity сразу после его onCreate() , но не привязывается, когда срабатывает некоторое обратное действие с Activity в роли прослушивателя. Итак, похоже, что Котлин снова смотрит на презентатора, но считает его неинициализированным. По-прежнему не получается, почему это происходит только на новых платформах.

Intereting Posts
Как читать переменную среды в Котлин? Создайте собственный класс View / ViewGroup в Anko DSL Как контролировать, когда импорт заменяется шаблоном в Android Studio в файлах Kotlin Тест JUnit в Котлине IllegalArgumentException: savedInstanceState Указано как Non-Null Null Как создать пользовательскую форму кнопки, но сохранить ее кликабельную и настраиваемую API автозаполнения Google Places дает ошибку API_NOT_CONNECTED в конфигурации Instant Apps Kotlin – getPendingIntent с синтаксисом нескольких флагов Получите enum constant, используя его значение Ошибка «Невозможно объединить dex» при использовании Room + Kotlin Как разрешить нарушение ограничения конечного ограничения в Котлине? Как избежать ошибки StackOverFlow в Java / Kotlin / IntelliJ IDEA? Как правильно обращаться с ошибками при использовании HTTP-клиента в Котлине? Как реализовать формулу Стирлинга с BigDecimal и BigInteger в Котлине? Тестирование JUnit с помощью студии KOTLIN android