Пользовательский интерфейс не обновляется данными при первом запуске приложения, но загружается, когда приложение закрывAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Пользовательский интерфейс не обновляется данными при первом запуске приложения, но загружается, когда приложение закрыв

Сообщение Anonymous »

У меня возникла проблема: при первом открытии приложения, когда пользователь проходит регистрацию, а затем переходит на главный экран, пользовательский интерфейс не загружает данные из базы данных и зависает на пустом белом экране на неопределенный срок. Но после закрытия и повторного открытия приложения данные загружаются как обычно.
Во время этого я также получаю следующие ошибки в журнале:
kotlinx.coroutines.JobCancellationException: задание было отменено; job=SupervisorJobImpl{Cancelling}@6cd224a
Часть кода приведена ниже:
Экран, который не загружается при первом запуске:
@Composable
fun DiaryComponentInit(
viewmodel: DiaryLogic = koinViewModel(),
navigator: Navigator?,
selectedDate: LocalDate = getCurrentDate()
) {
val state by viewmodel.homeState.collectAsState()

LaunchedEffect(selectedDate) {
viewmodel.fetchDataForDate(selectedDate)
}

state.nutrientsIndicator?.let { nutrientsData ->
DiaryComponent(
navigator = navigator,
userName = state.userName ?: "",
nutrientsData = nutrientsData,
waterIntakeData = state.waterIntake,
mealsData = state.meals,
selectedDate = state.selectedDate,
onDateChange = { viewmodel.fetchDataForDate(it) },
onWaterValueChange = { value, date ->
viewmodel.updateWaterIntake(value, date)
}
)
}
}

@Composable
private fun DiaryComponent(
navigator: Navigator?,
userName: String = "",
nutrientsData: NutrientsIndicatorState,
waterIntakeData: WaterIntakeState? = null,
mealsData: MealsState? = null,
selectedDate: LocalDate,
onDateChange: (LocalDate) -> Unit = {},
onWaterValueChange: (Float, LocalDate) -> Unit = { _, _ -> }
) {
val scrollState = rememberScrollState()
val navBarHeight = 85.dp
var calendarDialogShow by remember { mutableStateOf(false) }
val currentDate = remember { mutableStateOf("Today") }

Box(
modifier = Modifier
.fillMaxSize()
.safeDrawingPadding()
) {
Column(
modifier = Modifier
.fillMaxSize()
) {
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(scrollState)
.padding(16.dp)
) {
// Header: Profile and Calendar
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
// User Profile with Name
Row(
modifier = Modifier
.clickable {
navigator?.parent?.push(SettingsComponent())
},
verticalAlignment = Alignment.CenterVertically
) {
Card(
modifier = Modifier.size(45.dp),
shape = CircleShape,
backgroundColor = Color.Black
) {
Icon(
modifier = Modifier
.fillMaxSize()
.padding(8.dp),
painter = painterResource(Res.drawable.banana),
contentDescription = "Profile Picture",
tint = Color.Unspecified
)
}

Spacer(modifier = Modifier.width(8.dp))

Text(
text = userName,
fontSize = 16.sp,
color = Color.Black
)
}

// Date and Calendar
Row(
modifier = Modifier.clickable { calendarDialogShow = true },
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = currentDate.value,
fontSize = 16.sp,
color = Color.Black
)
Spacer(modifier = Modifier.width(8.dp))
Icon(
painter = painterResource(Res.drawable.calendar),
contentDescription = "Calendar Icon",
tint = Color(0xFF5CB85C),
modifier = Modifier.size(30.dp)
)
}
}

Spacer(modifier = Modifier.height(24.dp))

// Nutrients Section
Text(
modifier = Modifier.padding(bottom = 8.dp),
text = "Nutrients Indicator",
fontSize = 16.sp
)
NutrientsIndicatorComponent(nutrientsData)

Spacer(modifier = Modifier.height(24.dp))

// Water Intake Section
Text(
modifier = Modifier.padding(bottom = 8.dp),
text = "Water Intake",
fontSize = 16.sp
)
WaterIntakeComponent(
waterIntakeData = waterIntakeData,
selectedDate = selectedDate,
onWaterIntakeChange = { value, date ->
onWaterValueChange(value, date)
}
)

Spacer(modifier = Modifier.height(24.dp))

// Meals Section Header
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
modifier = Modifier.padding(bottom = 8.dp),
text = "Meals",
fontSize = 16.sp
)
Icon(
modifier = Modifier
.clickable { navigator?.parent?.push(CreateMealComponent(date = selectedDate)) }
.alignByBaseline()
.size(24.dp),
painter = painterResource(Res.drawable.add),
contentDescription = null
)
}
}

if (!mealsData?.meals.isNullOrEmpty()) {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.safeDrawingPadding()
.padding(bottom = navBarHeight, start = 16.dp, end = 16.dp)
) {
mealsData?.meals?.forEachIndexed { index, meal ->
item {
MealsItem(
mealType = meal.name ?: "Meal $index",
calories = meal.totalCalories.toString(),
time = meal.date ?: "Unknown"
)
}
}
}
} else {
Box(
modifier = Modifier
.fillMaxWidth()
) {
Text(
modifier = Modifier
.align(Alignment.Center)
.padding(16.dp),
text = "No meals for Today",
fontSize = 18.sp
)
}
}
}
}

if (calendarDialogShow) {
CalendarComponent(onDismiss = { formattedDate, newDate ->
calendarDialogShow = false
currentDate.value = formattedDate ?: currentDate.value
newDate?.let(onDateChange)
})
}
}

Вид модели экрана:
class DiaryLogic: ViewModel(), KoinComponent {
private val databaseRepo: DatabaseRepo by inject()

private val _homeState = MutableStateFlow(HomeUiState())
val homeState: StateFlow = _homeState

init {
getUserName()
updateDataForSelectedDate()
}

fun fetchDataForDate(date: LocalDate) {
viewModelScope.launch {
// Update selected date first
_homeState.value = _homeState.value.copy(selectedDate = date)

// Then fetch data for that date
getUserName()
getNutrientsData(date)
getWaterIntakeData(date)
getMealsData(date)
}
}

private fun updateDataForSelectedDate() {
val selectedDate = _homeState.value.selectedDate
getWaterIntakeData(selectedDate)
getNutrientsData(selectedDate)
getMealsData(selectedDate)
}

private fun getUserName() {
viewModelScope.launch {
val userName = databaseRepo.getUserName().toString()
_homeState.value = _homeState.value.copy(userName = userName)
}
}

private fun getNutrientsData(date: LocalDate) {
viewModelScope.launch {
val recommendedUserData = databaseRepo.getUser()
val nutrientsData = databaseRepo.getMealsByDate(date = date)
val totalCalories = nutrientsData.sumOf { it.totalCalories.toInt() }
val totalProteins = nutrientsData.sumOf { it.totalProteins.toInt() }
val totalFats = nutrientsData.sumOf { it.totalFats.toInt() }
val totalCarbs = nutrientsData.sumOf { it.totalCarbs.toInt() }

_homeState.value = _homeState.value.copy(nutrientsIndicator = NutrientsIndicatorState(
currentCalories = totalCalories,
currentProteins = totalProteins,
currentFats = totalFats,
currentCarbs = totalCarbs,

recommendedCalories = recommendedUserData!!.recommendedCalories,
recommendedProteins = recommendedUserData.recommendedProteins,
recommendedCarbs = recommendedUserData.recommendedCarbs,
recommendedFats = recommendedUserData.recommendedFats
))
}
}

private fun getWaterIntakeData(date: LocalDate) {
viewModelScope.launch {
val waterIntakeData = databaseRepo.getWaterIntake(date = date)
val recommendedUserData = databaseRepo.getUser()

val currentIntake = (waterIntakeData?.currentIntake ?: 0f).roundToDecimals(1)
val recommendedIntake = recommendedUserData?.recommendedWaterIntake ?: 1f

// Store the water intake data for the selected date
_homeState.value = _homeState.value.copy(
selectedDateWaterIntake = waterIntakeData,
waterIntake = WaterIntakeState(
currentWaterIntake = currentIntake,
recommendedWaterIntake = recommendedIntake,
lastUpdatedTime = waterIntakeData?.lastUpdatedTime,
currentWaterIntakePercentage = ((currentIntake / recommendedIntake) * 100).toInt()
)
)
}
}

private fun getMealsData(date: LocalDate) {
viewModelScope.launch {
val mealData = databaseRepo.getMealsByDate(date = date)
_homeState.value = _homeState.value.copy(
meals = MealsState(
meals = mealData.map { meal ->
MealState(
name = meal.name,
totalCalories = meal.totalCalories.toInt(),
date = meal.date.toString()
)
}
)
)
}
}

fun updateWaterIntake(value: Float, date: LocalDate) {
viewModelScope.launch {
val existingWaterIntake = _homeState.value.selectedDateWaterIntake ?:
databaseRepo.getWaterIntake(date = date)

val currentValue = existingWaterIntake?.currentIntake ?: 0f
val newValue = (currentValue + value).coerceAtLeast(0f)
val currentIntake = newValue.roundToDecimals(1)
val recommendedIntake = homeState.value.waterIntake?.recommendedWaterIntake ?: 1f

// Create new water intake data
val updatedWaterIntake = WaterIntake(
id = existingWaterIntake?.id ?: 0,
date = date,
currentIntake = currentIntake,
lastUpdatedTime = getCurrentTimeFormatted()
)

// Update database
databaseRepo.updateWaterIntake(updatedWaterIntake)

// Update state
_homeState.value = _homeState.value.copy(
selectedDateWaterIntake = updatedWaterIntake,
waterIntake = WaterIntakeState(
currentWaterIntake = currentIntake,
recommendedWaterIntake = recommendedIntake,
lastUpdatedTime = getCurrentTimeFormatted(),
currentWaterIntakePercentage = ((currentIntake / recommendedIntake) * 100).toInt()
)
)
}
}
}

data class HomeUiState(
val userName: String? = null,
val selectedDate: LocalDate = getCurrentDate(),
val selectedDateWaterIntake: WaterIntake? = null,
val nutrientsIndicator: NutrientsIndicatorState? = null,
val waterIntake: WaterIntakeState? = null,
val meals: MealsState? = null
)

data class NutrientsIndicatorState(
val currentProteins: Int? = null,
val currentFats: Int? = null,
val currentCarbs: Int? = null,
val currentCalories: Int? = null,

val recommendedProteins: Int? = null,
val recommendedFats: Int? = null,
val recommendedCarbs: Int? = null,
val recommendedCalories: Int? = null,
)

data class WaterIntakeState(
val currentWaterIntake: Float? = null,
val recommendedWaterIntake: Float? = null,
val lastUpdatedTime: String? = null,
val currentWaterIntakePercentage: Int? = null
)

data class MealsState(
val meals: List? = null
)

data class MealState(
val name: String? = null,
val totalCalories: Int? = null,
val date: String? = null
)

Модель просмотра экрана перед экраном дневника:
class BaseOnboardingLogic: ViewModel(), KoinComponent {
private val databaseRepo: DatabaseRepo by inject()
private val userRepo: UserRepo by inject()

private val _onboardingState = MutableStateFlow(OnboardingUiState())
val onboardingState: StateFlow = _onboardingState

fun setUserExists() {
viewModelScope.launch {
userRepo.setUserExists(true)
}
}

fun updateGoal(goal: String) {
_onboardingState.value = _onboardingState.value.copy(goal = goal)
}

fun updateGender(gender: String) {
_onboardingState.value = _onboardingState.value.copy(gender = gender)
}

fun updateActivity(activity: String) {
_onboardingState.value = _onboardingState.value.copy(activity = activity)
}

fun updateHeightFeet(heightFeet: Int) {
_onboardingState.value = _onboardingState.value.copy(heightFeet = heightFeet)
}

fun updateHeightInches(heightInches: Int) {
_onboardingState.value = _onboardingState.value.copy(heightInches = heightInches)
}

fun updateWeight(weight: Int) {
_onboardingState.value = _onboardingState.value.copy(weight = weight)
}

fun updateWeightUnit(weightUnit: String) {
_onboardingState.value = _onboardingState.value.copy(weightUnit = weightUnit)
}

fun updateAge(age: String) {
_onboardingState.value = _onboardingState.value.copy(age = age)
}

suspend fun saveUserDetails() {
val user = User(
name = "Adrian",
age = _onboardingState.value.age!!.toInt(),
gender = _onboardingState.value.gender!!,
heightFeet = _onboardingState.value.heightFeet!!,
heightInches = _onboardingState.value.heightInches!!,
weight = _onboardingState.value.weight!!.toFloat(),
weightUnit = _onboardingState.value.weightUnit!!,
goal = _onboardingState.value.goal!!,
activityLevel = _onboardingState.value.activity!!,
recommendedProteins = _onboardingState.value.recommendedProteins!!,
recommendedFats = _onboardingState.value.recommendedFats!!,
recommendedCarbs = _onboardingState.value.recommendedCarbs!!,
recommendedCalories = _onboardingState.value.recommendedCalories!!,
recommendedWaterIntake = _onboardingState.value.recommendedWaterIntake!!,
)
databaseRepo.saveUser(user)
}

fun calculatePFC(userDetails: OnboardingUiState): Map? {
// Retrieve user details
val weight = userDetails.weight!!.toInt()
val heightFeet = userDetails.heightFeet!!.toInt()
val heightInches = userDetails.heightInches!!.toInt()
val age = userDetails.age!!.toInt()
val gender = userDetails.gender
val activity = userDetails.activity
val goal = userDetails.goal

// Convert height to cm
val heightCm = (heightFeet * 30.48) + (heightInches * 2.54)

// Convert weight to kg if necessary
val weightKg = if (userDetails.weightUnit == "lbs") weight * 0.453592 else weight

// Calculate BMR using Harris-Benedict Equation
val bmr = when (gender) {
"Male" -> 88.362 + (13.397 * weightKg.toInt()) + (4.799 * heightCm) - (5.677 * age)
"Female" -> 447.593 + (9.247 * weightKg.toInt()) + (3.098 * heightCm) - (4.330 * age)
else -> return null
}

// Adjust BMR based on activity level
val totalCalories = when (activity) {
"Sedentary" -> bmr * 1.2
"Low active" -> bmr * 1.375
"Active" -> bmr * 1.55
"Very active" -> bmr * 1.825
else -> bmr
}

// Define PFC ratios based on goal
val (proteinRatio, fatRatio, carbRatio) = when (goal) {
"Lose weight" -> Triple(0.4, 0.3, 0.3)
"Keep weight" -> Triple(0.3, 0.3, 0.4)
"Gain weight" -> Triple(0.45, 0.2, 0.35)
else -> Triple(0.3, 0.3, 0.4) // Default: maintenance
}

// Calculate grams of Protein, Fat, and Carbs
val proteinGrams = (totalCalories * proteinRatio / 4).toInt()
val fatGrams = (totalCalories * fatRatio / 9).toInt()
val carbGrams = (totalCalories * carbRatio / 4).toInt()
val waterGrams = if (gender == "Male") 3.7 else 2.5

_onboardingState.value = _onboardingState.value.copy(recommendedProteins = proteinGrams)
_onboardingState.value = _onboardingState.value.copy(recommendedFats = fatGrams)
_onboardingState.value = _onboardingState.value.copy(recommendedCarbs = carbGrams)
_onboardingState.value = _onboardingState.value.copy(recommendedCalories = totalCalories.toInt())
_onboardingState.value = _onboardingState.value.copy(recommendedWaterIntake = waterGrams.toFloat())

// Return PFC distribution and calories
return mapOf(
"protein" to proteinGrams,
"fat" to fatGrams,
"carbs" to carbGrams,
"calories" to totalCalories.toInt()
)
}
}

data class OnboardingUiState(
val goal: String? = null,
val gender: String? = null,
val activity: String? = null,
val heightFeet: Int? = null,
val heightInches: Int? = null,
val weight: Int? = null,
val weightUnit: String? = null,
val age: String? = null,
val recommendedProteins: Int? = null,
val recommendedFats: Int? = null,
val recommendedCarbs: Int? = null,
val recommendedCalories: Int? = null,
val recommendedWaterIntake: Float? = null
)


Подробнее здесь: https://stackoverflow.com/questions/793 ... -closed-an
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»