Методы Android ViewModel провалится после первого успешного исполнения - Управление государством или вопрос о параллелизAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Методы Android ViewModel провалится после первого успешного исполнения - Управление государством или вопрос о параллелиз

Сообщение Anonymous »

В моем приложении Android у меня есть UServiewModel, которая обрабатывает различные операции, связанные с пользователем (регистрация, вход в систему, обновление имени пользователя, изменение пароля и т. Д.). Проблема заключается в том, что после того, как один из этих методов успешно выполняется, последующие вызовы к другим методам в UserviewModel не отражают изменения в пользовательском интерфейсе или локальных данных, даже если базовый пользовательский размер успешно завершает операции (подтверждено журналами). Эта проблема влияет на все методы в USERVIEWMODEL, а не только на обновление имени пользователя.package com.kianmahmoudi.android.shirazgard.viewmodel

import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kianmahmoudi.android.shirazgard.repository.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
import com.kianmahmoudi.android.shirazgard.data.UiState
import com.parse.ParseUser
import timber.log.Timber

@HiltViewModel
class UserViewModel @Inject constructor(
private val userRepository: UserRepository
) : ViewModel() {

private val _registerState = MutableLiveData(UiState.Idle)
val registerState: LiveData = _registerState

private val _loginState = MutableLiveData(UiState.Idle)
val loginState: LiveData = _loginState

private val _logoutState = MutableLiveData(UiState.Idle)
val logoutState: LiveData = _logoutState

private val _deleteAccountState = MutableLiveData(UiState.Idle)
val deleteAccountState: LiveData = _deleteAccountState

private val _passwordChangeState = MutableLiveData(UiState.Idle)
val passwordChangeState: LiveData = _passwordChangeState

private val _passwordVerificationState = MutableLiveData(UiState.Idle)
val passwordVerificationState: LiveData = _passwordVerificationState

private val _profileImageState = MutableLiveData(UiState.Idle)
val profileImageState: LiveData = _profileImageState

private val _usernameState = MutableLiveData(UiState.Idle)
val usernameState: LiveData = _usernameState

private val _profileImageDeletionState = MutableLiveData(UiState.Idle)
val profileImageDeletionState: LiveData = _profileImageDeletionState

fun registerUser(username: String, password: String) {
if (_registerState.value is UiState.Loading) return

viewModelScope.launch {
_registerState.value = UiState.Loading
runCatching {
userRepository.registerUser(username, password)
}.onSuccess {
_registerState.value = UiState.Success(it)
}.onFailure {
_registerState.value = UiState.Error(it.localizedMessage ?: "Error registering")
}
}
}

fun loginUser(username: String, password: String) {
if (_loginState.value is UiState.Loading) return

viewModelScope.launch {
_loginState.value = UiState.Loading
runCatching {
userRepository.loginUser(username, password)
}.onSuccess {
_loginState.value = UiState.Success(it)
}.onFailure {
_loginState.value = UiState.Error(it.localizedMessage ?: "Error logging in")
}
}
}

fun logout() {
if (_logoutState.value is UiState.Loading) return

viewModelScope.launch {
_logoutState.value = UiState.Loading
runCatching {
userRepository.logout()
}.onSuccess {
_logoutState.value = UiState.Success(Unit)
}.onFailure {
_logoutState.value = UiState.Error(it.localizedMessage ?: "Error logging out")
}
}
}

fun updateUsername(newUsername: String) {
if (_usernameState.value is UiState.Loading) return

viewModelScope.launch {
_usernameState.value = UiState.Loading
try {
val success = userRepository.updateUsername(newUsername)
if (success) {
// Force refresh the current user data
ParseUser.getCurrentUser()?.fetchInBackground()
_usernameState.value = UiState.Success(newUsername)
} else {
_usernameState.value = UiState.Error("Failed to update username")
}
} catch (e: Exception) {
_usernameState.value = UiState.Error(e.localizedMessage ?: "Error updating username")
}
}
}

fun uploadProfileImage(imageUri: Uri) {
if (_profileImageState.value is UiState.Loading) return

viewModelScope.launch {
_profileImageState.value = UiState.Loading
runCatching {
userRepository.uploadProfileImage(imageUri)
userRepository.getProfileImageUrl()
}.onSuccess { url ->
_profileImageState.value = UiState.Success(url)
}.onFailure {
_profileImageState.value =
UiState.Error(it.localizedMessage ?: "Image upload error")
}
}
}

fun deleteProfileImage() {
if (_profileImageDeletionState.value is UiState.Loading) return

viewModelScope.launch {
_profileImageDeletionState.value = UiState.Loading
runCatching { userRepository.deleteProfileImage() }
.onSuccess {
_profileImageDeletionState.value = UiState.Success(true)
_profileImageState.value = UiState.Success("")
}.onFailure {
_profileImageDeletionState.value =
UiState.Error(it.localizedMessage ?: "Error deleting image")
}
}
}

fun fetchProfileImageUrl() {
if (_profileImageState.value is UiState.Loading) return

viewModelScope.launch {
_profileImageState.value = UiState.Loading
runCatching { userRepository.getProfileImageUrl() }
.onSuccess {
_profileImageState.value = UiState.Success(it)
}.onFailure {
_profileImageState.value =
UiState.Error(it.localizedMessage ?: "Error fetching profile image url")
}
}
}

fun changePassword(newPassword: String) {
if (_passwordChangeState.value is UiState.Loading) return

viewModelScope.launch {
_passwordChangeState.value = UiState.Loading
runCatching { userRepository.changePassword(newPassword) }
.onSuccess {
_passwordChangeState.value = UiState.Success(true)
}.onFailure {
_passwordChangeState.value =
UiState.Error(it.localizedMessage ?: "Error changing password")
}
}
}

fun verifyCurrentPassword(password: String) {
if (_passwordVerificationState.value is UiState.Loading) return

viewModelScope.launch {
_passwordVerificationState.value = UiState.Loading
runCatching { userRepository.isCurrentPasswordCorrect(password) }
.onSuccess {
_passwordVerificationState.value = UiState.Success(it)
}.onFailure {
_passwordVerificationState.value =
UiState.Error(it.localizedMessage ?: "Password verification failed")
}
}
}

fun deleteAccount() {
if (_deleteAccountState.value is UiState.Loading) return

viewModelScope.launch {
_deleteAccountState.value = UiState.Loading
runCatching { userRepository.deleteAccount() }
.onSuccess {
_deleteAccountState.value = UiState.Success(true)
}.onFailure {
_deleteAccountState.value =
UiState.Error(it.localizedMessage ?: "Account deletion failed")
}
}
}

fun resetUsernameState() {
Timber.d("UserViewModel: resetUsernameState called")
_usernameState.postValue(UiState.Idle)
}

}
< /code>
код моего пользователя-репозиции < /p>
package com.kianmahmoudi.android.shirazgard.repository

import android.content.Context
import android.net.Uri
import com.parse.ParseCloud
import com.parse.ParseFile
import com.parse.ParseUser
import com.parse.SaveCallback
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.suspendCancellableCoroutine
import org.json.JSONObject
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

class UserRepositoryImpl @Inject constructor(
@ApplicationContext private val context: Context
) : UserRepository {

override suspend fun registerUser(userName: String, password: String): ParseUser {
return suspendCoroutine { continuation ->
ParseUser().apply {
username = userName
setPassword(password)
signUpInBackground { e ->
if (e == null) {
continuation.resume(this)
} else {
continuation.resumeWithException(e)
}
}
}
}
}

override suspend fun loginUser(userName: String, password: String): ParseUser {
return suspendCoroutine { continuation ->
ParseUser.logInInBackground(userName, password) { user, e ->
if (e == null) {
continuation.resume(user)
} else {
continuation.resumeWithException(e)
}
}
}
}

override suspend fun changePassword(newPassword: String): Boolean {
return suspendCancellableCoroutine { continuation ->
val currentUser = ParseUser.getCurrentUser()
if (currentUser != null) {
currentUser.setPassword(newPassword)
currentUser.saveInBackground { e ->
if (e == null && continuation.isActive) {
continuation.resume(true)
} else if (continuation.isActive) {
continuation.resumeWithException(
e ?: Exception("Failed to change password")
)
}
}
} else {
continuation.resumeWithException(Exception("User not logged in"))
}
}
}

override suspend fun uploadProfileImage(imageUri: Uri): Boolean {
return suspendCoroutine { continuation ->
val user = ParseUser.getCurrentUser()
val bytes = context.contentResolver.openInputStream(imageUri)?.readBytes()
?: throw Exception("Failed to read image")

val parseFile = ParseFile("profile_${user.objectId}.jpg", bytes)
parseFile.saveInBackground(SaveCallback { e ->
if (e == null) {
user.put("profileImage", parseFile)
user.saveInBackground { e ->
if (e == null) {
continuation.resume(true)
} else {
continuation.resumeWithException(e)
}
}
} else {
continuation.resumeWithException(e)
}
})
}
}

override suspend fun getProfileImageUrl(): String {
return suspendCoroutine { continuation ->
val url = ParseUser.getCurrentUser().getParseFile("profileImage")?.url
if (url != null) {
continuation.resume(url)
} else {
continuation.resumeWithException(Exception("No profile image found"))
}
}
}

override suspend fun updateUsername(newUsername: String): Boolean {
return suspendCancellableCoroutine { continuation ->
val user = ParseUser.getCurrentUser()
if (user != null) {
user.username = newUsername
user.saveInBackground { e ->
if (e == null) {
continuation.resume(true)
} else {
continuation.resumeWithException(e)
}
}
} else {
continuation.resumeWithException(Exception("User not logged in"))
}
}
}

override suspend fun deleteProfileImage(): Boolean {
return suspendCoroutine { continuation ->
ParseUser.getCurrentUser().apply {
remove("profileImage")
saveInBackground { e ->
if (e == null) {
continuation.resume(true)
} else {
continuation.resumeWithException(e)
}
}
}
}
}

override suspend fun deleteAccount(): Boolean {
return suspendCoroutine { continuation ->
ParseUser.getCurrentUser().deleteInBackground { e ->
if (e == null) {
logout()
continuation.resume(true)
} else {
continuation.resumeWithException(e)
}
}
}
}

override fun logout() {
ParseUser.logOutInBackground()
}

override suspend fun isCurrentPasswordCorrect(password: String): Boolean {
return suspendCancellableCoroutine { continuation ->
try {
val currentUser = ParseUser.getCurrentUser()
if (currentUser != null) {
val params = hashMapOf("username" to currentUser.username, "password" to password)
ParseCloud.callFunctionInBackground("verifyPassword", params) { result, e ->
if (e == null) {
try {
val jsonObject = JSONObject(result as Map)
val success = jsonObject.getBoolean("success")
if (success) {
continuation.resume(true)
} else {
val error = jsonObject.getString("error")
continuation.resumeWithException(Exception(error))
}
} catch (jsonException: Exception) {
continuation.resumeWithException(jsonException)
}
} else {
continuation.resumeWithException(e)
}
}
} else {
continuation.resumeWithException(Exception("User not logged in"))
}
} catch (e: Exception) {
continuation.resumeWithException(Exception("Failed to verify password: ${e.localizedMessage}"))
}
}
}
}
< /code>
Одним из классов, которые возникают этой проблемой, является EditProfileFragment < /p>
Редактировать код фрагмента профиля < /p>
package com.kianmahmoudi.android.shirazgard.fragments

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import com.kianmahmoudi.android.shirazgard.R
import com.kianmahmoudi.android.shirazgard.data.UiState
import com.kianmahmoudi.android.shirazgard.databinding.FragmentEditProfileBinding
import com.kianmahmoudi.android.shirazgard.viewmodel.UserViewModel
import com.parse.ParseUser
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber

@AndroidEntryPoint
class EditProfileFragment : Fragment(R.layout.fragment_edit_profile) {

private lateinit var binding: FragmentEditProfileBinding
private val userViewModel: UserViewModel by viewModels()

private val pickImageLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
result.data?.data?.let { uri ->
uploadProfileImage(uri)
}
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.btnUpload.setOnClickListener { openImagePicker() }
binding.btnDelete.setOnClickListener { deleteProfileImage() }
binding.btnSave.setOnClickListener {
updateUsername()
}

viewLifecycleOwner.lifecycleScope.launch {
userViewModel.profileImageState.observe(viewLifecycleOwner) { result ->
when (result) {
is UiState.Success -> {
Glide.with(requireContext())
.load(result.data)
.placeholder(R.drawable.person_24px)
.circleCrop()
.into(binding.profileImage)
}

is UiState.Error -> {
showToast(result.message)
}

is UiState.Loading -> {

}

UiState.Idle -> {}

}
}
}
viewLifecycleOwner.lifecycleScope.launch {
userViewModel.profileImageDeletionState.observe(viewLifecycleOwner) { result ->
when (result) {
is UiState.Loading -> {

}

is UiState.Success -> {
showToast("تصویر پروفایل با موفقیت حذف شد")
binding.profileImage.setImageResource(R.drawable.person_24px)

}

is UiState.Error -> {
showToast(result.message)
}

UiState.Idle -> {}
}
}
}
viewLifecycleOwner.lifecycleScope.launch {
userViewModel.usernameState.observe(viewLifecycleOwner) { result ->
when (result) {
is UiState.Success -> {
Timber.i("Username updated to: ${ParseUser.getCurrentUser()?.username}")
Timber.i("Username: ${result.data}")
showToast("نام کاربری با موفقیت به‌روزرسانی شد")
findNavController().navigateUp()
}

is UiState.Error -> {
Timber.i("Username error: ${result.message}")
showToast(result.message)
}

UiState.Loading -> {
Timber.d("EditProfileFragment: usernameState is loading")
}

UiState.Idle -> {
Timber.d("EditProfileFragment: usernameState is idle")
}
}
if (result != UiState.Idle) {
userViewModel.resetUsernameState()
}
}
}

val currentUser = ParseUser.getCurrentUser()
binding.etUsername.setText(currentUser?.username)
userViewModel.fetchProfileImageUrl()

}

private fun openImagePicker() {
val intent = Intent(Intent.ACTION_PICK).apply {
type = "image/*"
}
pickImageLauncher.launch(intent)
}

private fun uploadProfileImage(uri: Uri) {
userViewModel.uploadProfileImage(uri)
}

private fun deleteProfileImage() {
userViewModel.deleteProfileImage()
}

private fun updateUsername() {
val newUsername = binding.etUsername.text.toString().trim()
Timber.d("EditProfileFragment: updateUsername called with newUsername: $newUsername")
if (userViewModel.usernameState.value !is UiState.Loading) {
if (newUsername.isNotEmpty()) {
userViewModel.updateUsername(newUsername)
Timber.d("EditProfileFragment: userViewModel.updateUsername called")
} else {
showToast("نام کاربری نمی‌تواند خالی باشد")
Timber.d("EditProfileFragment: newUsername is empty")
}
} else {
Timber.d("EditProfileFragment: updateUsername is already loading")
}
}

private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT)
.show()
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentEditProfileBinding.inflate(inflater)
return binding.root
}

}


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

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Асинсио порядок исполнения против трио порядок исполнения
    Anonymous » » в форуме Python
    0 Ответы
    4 Просмотры
    Последнее сообщение Anonymous
  • Асинсио порядок исполнения против трио порядок исполнения
    Anonymous » » в форуме Python
    0 Ответы
    5 Просмотры
    Последнее сообщение Anonymous
  • Исчезновение результатов после успешного исполнения в блоггере
    Anonymous » » в форуме Html
    0 Ответы
    2 Просмотры
    Последнее сообщение Anonymous
  • Исчезновение результатов после успешного исполнения в блоггере
    Anonymous » » в форуме Html
    0 Ответы
    2 Просмотры
    Последнее сообщение Anonymous
  • Исчезновение результатов после успешного исполнения в блоггере
    Anonymous » » в форуме Html
    0 Ответы
    4 Просмотры
    Последнее сообщение Anonymous

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