Мои модели представления наследуются от базовой модели представления:
Код: Выделить всё
abstract class ArrowWordsViewModel(
private val dispatcher: CoroutineDispatcher = Dispatchers.IO.also { println("CPT ERROR Parent constructor") }
) :
ViewModel() {
init {
println("CPT ERROR INIT")
computeViewModelInternally(true)
}
open suspend fun computeViewModel() {}
private fun computeViewModelInternally() {
Timber.d("CPT ERROR - computeViewModelInternal")
viewModelScope.launch(dispatcher + CoroutineExceptionHandler { _, throwable ->
viewModelScope.launch(Dispatchers.Main) {
println("CPT ERROR THROWABLE- ${throwable.javaClass.name}")
}
}) {
println("CPT ERROR computeViewModel parent")
computeViewModel()
}
}
}
Код: Выделить всё
@HiltViewModel
class AdsViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle,
private val preferences: ArrowWordsPreferences,
private val fake: Int
) : ArrowWordsViewModel() {
val isOnBoardingContextTest= savedStateHandle.get(ScreenArgs.ADS_IS_ONBOARDING_EXTRA).also { println("CPT ERROR ATTRIBUTE") }
val isOnBoardingContext = MutableStateFlow(false)
val showAlertDialog = MutableStateFlow(false)
override suspend fun computeViewModel() {
println("CPT ERROR computeViewModel")
super.computeViewModel()
isOnBoardingContext.value = savedStateHandle.get(ScreenArgs.ADS_IS_ONBOARDING_EXTRA) ?: false
}
}
Код: Выделить всё
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
@Provides
@Singleton
fun providePreferences(@ApplicationContext context: Context): ArrowWordsPreferences =
ArrowWordsPreferences(context)
@Provides
fun provideFake() : Int =
1.also { println("CPT ERROR - PROVIDE FAKE") }
}
Код: Выделить всё
@Composable
fun AdsScreen(
modifier: Modifier = Modifier,
viewModel: AdsViewModel = hiltViewModel(),
onBackClicked: () -> Unit,
onOnBoardingFinished: () -> Unit
) {
//...
}
Как видите, я добавил логи и поддельные инъекции, чтобы попытаться понять поток моего кода.
В 99% случаев, когда все идет хорошо, логи выдают следующий результат:
Код: Выделить всё
CPT ERROR - PROVIDE FAKE
CPT ERROR Parent constructor
CPT ERROR INIT
CPT ERROR ATTRIBUTE
CPT ERROR computeViewModel parent
CPT ERROR computeViewModel
Код: Выделить всё
CPT ERROR - PROVIDE FAKE
CPT ERROR Parent constructor
CPT ERROR INIT
CPT ERROR computeViewModel parent
CPT ERROR computeViewModel
CPT ERROR ATTRIBUTE
CPT ERROR THROWABLE- java.lang.NullPointerException
Согласно документации Kotlin:
Во время инициализации экземпляра блоки инициализатора выполняются в том же порядке, в котором они появляются в теле класса, чередуясь с инициализаторы свойств:
Поэтому я делаю вывод, что в моем случае конструктор класса ArrowWordsViewModel вызывается ДО окончания внедрения Hilt в конструктор класса AdsViewModel . Поскольку вызывается основной конструктор класса ArrowWordsViewModel, он затем разрешает вызов блока init, который запускает методы ComputeViewModel и приводит к NullPointerExceptions, поскольку Hilt этого не делает. кажется, завершил внедрение (поскольку атрибуты класса AdsViewModel вызываются позже).
Как я могу переработать свой код, чтобы гарантировать, что Hilt завершил внедрение перед вызовом блок init родительского класса, который запускает загрузку данных в моем случае?
Обратите внимание, что код намеренно упрощен, и я хотел бы сохранить эту систему «функций, которые загружает данные", если это возможно.
Подробнее здесь: https://stackoverflow.com/questions/792 ... -compose-v
Мобильная версия