I'm developing an Android app using Kotlin. I need to display pictures from Cloud Storage on the screens. Now, pictures are displayed but they flickers. I can't find infomation written in Kotlin and I have no idea why this is happening. This is my current code.
@Composable
fun UserInfo(navController: NavController, name: String, uid: String) {
val storage = Firebase.storage
val userRef = storage
.reference
.child("users/${uid}/photos")
.child(name)
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
val ONE_MEGABYTE: Long = 1024 * 1024
userRef.getBytes(ONE_MEGABYTE).addOnSuccessListener {
bitmap = BitmapFactory.decodeByteArray(it, 0, it.size)
}
...
if (userRef != null) {
Image(
painter = rememberImagePainter(bitmap),
contentScale = ContentScale.FillBounds,
contentDescription = null,
modifier = Modifier
.width(100.dp)
.height(100.dp)
.clip(CircleShape)
)
...
Could someone help me? Thank you.
I've moved the codes to Storage Class like this.
class Storage {
val storage = Firebase.storage
@Composable
fun GetPhoto(uid: String, name: String): Bitmap? {
val userRef = storage.reference
.child("users/${uid}/photos")
.child(name)
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
val ONE_MEGABYTE: Long = 1024 * 1024
userRef.getBytes(ONE_MEGABYTE).addOnSuccessListener {
bitmap = BitmapFactory.decodeByteArray(it, 0, it.size)
}
return bitmap
}
}
And this is UserInfo View now.
@Composable
fun UserInfo(navController: NavController, name: String, uid: String) {
...
storage.GetPhoto(uid, name)
val bitmap =
Image(
painter = rememberImagePainter(storage.GetPhoto(uid, name)),
contentScale = ContentScale.FillBounds,
...
This is my whole code of UserInfo View.
@Composable
fun UserInfo(navController: NavController, name: String, uid: String) {
val storage = Storage()
Column(
modifier = Modifier
.background(Beige)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Row(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
horizontalArrangement = Arrangement.Center
)
{
storage.GetPhoto(uid, name)
Image(
painter = rememberImagePainter(storage.GetPhoto(uid, name)),
contentScale = ContentScale.FillBounds,
contentDescription = null,
modifier = Modifier
.width(100.dp)
.height(100.dp)
.clip(CircleShape)
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
horizontalArrangement = Arrangement.Center
)
{
Button(modifier = Modifier.wrapContentWidth(),
colors = ButtonDefaults.textButtonColors(
backgroundColor = Pink,
contentColor = Brown,
disabledContentColor = Color.LightGray
),
onClick = {
navController.navigate("PostHistory")
}
) {
Text(text = "Posts", fontSize = 20.sp)
}
}
CodePudding user response:
Would you mind trying this?, disregarding the changes you made like creating another class (Storage
) and just resorting back to the older version of your UserInfo
?
I made a reference from a Firebase
image fetching that I have, I'm wrapping all firebase components inside the LaunchedEffect
that will not trigger on the next re-composition
, in your case once the Bitmap
receives a new value the UserInfo
will re-compose
.
@Composable
fun UserInfo(navController: NavController, name: String, uid: String) {
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
LaunchedEffect(Unit) {
val storage = Firebase.storage
val userRef = storage
.reference
.child("users/${uid}/photos")
.child(name)
val ONE_MEGABYTE: Long = 1024 * 1024
userRef.getBytes(ONE_MEGABYTE).addOnSuccessListener {
bitmap = BitmapFactory.decodeByteArray(it, 0, it.size)
}
}
if (bitmap != null) {
Image(
painter = rememberImagePainter(bitmap),
contentScale = ContentScale.FillBounds,
contentDescription = null,
modifier = Modifier
.width(100.dp)
.height(100.dp)
.clip(CircleShape)
)
}
}