Search code examples
androidfirebasekotlinandroid-jetpack-composefirebase-storage

Picture from Firebase is not updating in compose


When i click picture it updates in firebase storage, but doesn't updates in my ui. But if i click this picture again, it will update in the ui.

Code:

var user by remember {
    mutableStateOf(
        if(signInWithGoogle) {
            User(
                profilePictureUrl = userData?.profilePictureUrl,
                userName = userData?.userName
            )
        } else {
            User(
                profilePictureUrl = signInEmailVM.getSignedInUser()?.photoUrl.toString(),
                userName = signInEmailVM.getSignedInUser()?.displayName
            )
        }
    )
}

//Photo picker
val singlePhotoPickerLauncher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.PickVisualMedia(),
    //Upload image to firebase and change profile picture
    onResult = { uri ->
        if(uri != null) {
            scope.launch {
                if(signInEmailVM.updateUserProfile(image = uri, name = "BRBX")) {
                    Toast.makeText(
                        context,
                        "Изменения сохранены",
                        Toast.LENGTH_SHORT
                    ).show()
                    user = User(
                        profilePictureUrl = signInEmailVM.getSignedInUser()?.photoUrl.toString(),
                        userName = signInEmailVM.getSignedInUser()?.displayName
                    )
                } else {
                    Toast.makeText(
                        context,
                        "Что-то пошло не так",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
        }
    }
)

AsyncImage(
    model = user.profilePictureUrl,
    contentDescription = "Profile picture",
    modifier = Modifier.fillMaxSize(),
    contentScale = ContentScale.Crop
)

I tried to move the creation of a new instance of the user object, but result was stil the same. I tried to run top part of code, not in a coroutine, didn't help. I think problem is compose and his recompositions. But if the picture was already updated, next time i click it, it will showed from the first try. If you need, here is code for updating user picture:

suspend fun updateUserProfile(image: Uri, name: String): Boolean {
    val storageRef = FirebaseStorage.getInstance().reference.child("Users/${firebaseAuth.currentUser?.uid}/${image.lastPathSegment}")
    val upload = storageRef.putFile(image)

    val result = CompletableDeferred<Boolean>()
    upload.addOnCompleteListener {
        result.complete(it.isSuccessful)
    }

    storageRef.downloadUrl.addOnSuccessListener { uri ->
        val profileUpdates = userProfileChangeRequest {
            displayName = name
            photoUri = Uri.parse(uri.toString())
        }
        firebaseAuth.currentUser?.updateProfile(profileUpdates)?.addOnCompleteListener {
            result.complete(it.isSuccessful)
        }
    }

    return result.await()
}

Solution

  • Finally after three hours i found solution. Problem wasn't in recompositions, it was in logic

    suspend fun updateUserProfile(image: Uri, name: String): Boolean {
        val storageRef = FirebaseStorage.getInstance().reference.child("Users/${firebaseAuth.currentUser?.uid}/${image.lastPathSegment}")
        val upload = storageRef.putFile(image)
    
        val result = CompletableDeferred<Boolean>()
        upload.addOnSuccessListener {
            storageRef.downloadUrl.addOnSuccessListener { uri ->
                val profileUpdates = userProfileChangeRequest {
                    displayName = name
                    photoUri = Uri.parse(uri.toString())
                }
                firebaseAuth.currentUser?.updateProfile(profileUpdates)?.addOnSuccessListener {
                    result.complete(true)
                }
            }
        }
    
        return result.await()
    }
    

    This worked for me