Я прохожу курс для разработчиков Android по основам Android с помощью Compose. Я нахожусь на модуле 6.2 «Использование комнаты для сохранения данных» (уровень моих текущих знаний в области разработки приложений для Android на данный момент, когда я начинаю).
Я работаю над приложением для заметок под названием Outlook Planner
Простое приложение для заметок + простой прогноз погоды. И я основываю структуру своего приложения на Inventory App, найденном на текущем уровне, на котором я прохожу курс.
Мои модели представления HomeViewModel и MakePlanViewModel извлекаются из AppViewModelProvider для сбора информации из базы данных SQLite + Room для отображения списка заметок и операций вставки/обновления соответственно. И они будут использоваться страницами «Home» и «MakePlan» соответственно.
Однако во время выполнения приложение вылетает, и эта ошибка, которую я не могу устранить, напечатана на этой фотографии
Или
java.lang.ClassCastException: android.app.Application cannot be cast to com.example.outlook.planner.OutlookPlannerApplication
at com.example.outlook.planner.ui.AppViewModelProviderKt.outlookPlannerApplication(AppViewModelProvider.kt:42)
at com.example.outlook.planner.ui.AppViewModelProvider$Factory$1$2.invoke(AppViewModelProvider.kt:32)
at com.example.outlook.planner.ui.AppViewModelProvider$Factory$1$2.invoke(AppViewModelProvider.kt:30)
Я ожидал, что приложение будет работать нормально; Я получал доступ к своей базе данных, чтобы отображать заметки на домашней странице и вставлять/редактировать заметки со страницы MakePlan.
К сожалению, учитывая мои нынешние ограниченные знания в области разработки приложений для Android, я не знаю, с чего начать диагностику проблемы и ее устранение.
Я делаю это приложение для школьного проекта, и мне действительно не хочется создавать его с нуля, поскольку я уже много поработал над этим (и не помогают онлайн-уроки по созданию приложения для заметок). в Kotlin + Jetpack Compose уже несколько лет, и у них нет единого базового метода, который бы напоминал все, что Google предлагает в своих примерах).
Любая помощь будет оценена по достоинству. Спасибо.
РЕДАКТИРОВАТЬ Вот код, который вы можете просмотреть:
1. Приложение OutlookPlanner
class OutlookPlannerApplication : Application() {
/**
* AppContainer instance used by the rest of classes to obtain dependencies
*/
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
container = AppDataContainer(this)
}
package com.example.outlook.planner.ui
import android.app.Application
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.outlook.planner.OutlookPlannerApplication
import com.example.outlook.planner.ui.pages.home.HomeViewModel
import com.example.outlook.planner.ui.pages.makeplan.MakePlanViewModel
/**
* Provides Factory to create instance of ViewModel for the entire Outlook Planner app
*/
object AppViewModelProvider {
val Factory = viewModelFactory {
/**
* Initializer for [MakePlanViewModel]
*/
initializer {
MakePlanViewModel(
planRepository = outlookPlannerApplication().container.planRepository
)
// MakePlanViewModel()
}
/**
* Initializer for [HomeViewModel]
*/
initializer {
HomeViewModel(
planRepository = outlookPlannerApplication().container.planRepository
)
}
}
}
/**
* Extension function to queries for [Application] object and returns an instance of
* [OutlookPlannerApplication].
*/
fun CreationExtras.outlookPlannerApplication(): OutlookPlannerApplication =
(this[AndroidViewModelFactory.APPLICATION_KEY] as OutlookPlannerApplication)
/**
* ViewModel to retrieve all items in the Room database.
*/
class HomeViewModel(planRepository: PlanRepository): ViewModel() {
val homeUiState: StateFlow<HomeUiState> =
planRepository.getPlanAll().map { HomeUiState(it) }
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
initialValue = HomeUiState()
)
companion object {
private const val TIMEOUT_MILLIS = 5_000L
}
}
class MakePlanViewModel(
savedStateHandle: SavedStateHandle? = null,
private val planRepository: PlanRepository
): ViewModel() {
/**
* Make Plan UI state
*/
var makePlanUiState by mutableStateOf(MakePlanUiState())
private set
/**
* Initialize private values in presence of an existing Plan object
*/
fun initialize(planEntity: PlanEntity) {
/** DO SOMETHING */
}
// init {
// if (savedStateHandle != null) {
// viewModelScope.launch {
// makePlanUiState = planRepository.getPlanOne(planId)
// .filterNotNull()
// .first()
// .toItemUiState(true)
// }
// }
// }
/**
* Check that no fields are empty
*/
private fun validateInput(planCheck: Plan = makePlanUiState.plan): Boolean {
return with(planCheck) {
note.isNotBlank()
}
}
/**
* Updates the [makePlanUiState] with the value provided in the argument. This method also triggers
* a validation for input values.
*/
fun updateUiState(planUpdated: Plan) {
makePlanUiState = MakePlanUiState(
plan = planUpdated,
fieldNotEmptyAll = validateInput(planUpdated)
)
}
/**
* Insert + Update current plan
*/
suspend fun planUpsert() {
if (validateInput()) {
planRepository.planUpsert(makePlanUiState.plan.toEntity())
}
}
}
Если есть еще вопросы, дайте мне знать или git клонируйте мой проект здесь и откройте в Android Studio.
Готово, @tyczj! Взгляни.
Вероятно, вы не зарегистрировали свое пользовательское Приложение в манифесте.
Согласно документации (выделено мной):
Вы можете предоставить свою собственную реализацию, создав подкласс и указав полное имя этого подкласса в качестве атрибута «android:name» в теге AndroidManifest.xml.
Так:
В AndroidManifest.xml
должно быть что-то вроде:
<application
android:name = "com.example.outlook.planner.OutlookPlannerApplication"
....
</application>
Без этого система не будет знать о вашем пользовательском приложении и инициализирует экземпляр класса по умолчанию Application
, что приводит к ошибке при попытке привести его к ожидаемому типу.
Большое спасибо за эту информацию! Очень жаль, что в курсе для начинающих это не было отмечено.
покажите некоторый код, где находится ваш класс провайдера, в котором отображается ошибка