I have this composable that used to work fine, but now after some libraries update it doesn't.
I'm using a ViewModel
to save an image returned from ActivityResultContracts.TakePicture()
and show it in an Image
within a Box
.
The PhotoButton
composable is working fine and return the correct image url, but the image string in my main composable is always null.
SamplePage.kt
@Composable
fun SamplePage(navController: NavController) {
val inputViewModel = InputViewModel()
val context = LocalContext.current
Column{
InputFields(inputViewModel, navController, setPerm)
}
}
@Composable
fun InputFields(inputViewModel: InputViewModel, navController: NavController) {
val image: String by inputViewModel.image.observeAsState("")
Column() {
Row(verticalAlignment = Alignment.CenterVertically) {
Box(contentAlignment = Alignment.Center) {
val painter = rememberImagePainter(data = image)
Image(
painter = painter,
contentScale = ContentScale.FillWidth,
contentDescription = null
)
if (painter.state !is ImagePainter.State.Success) {
Icon(
painter = painterResource(id = R.drawable.icon),
contentDescription = null
)
}
}
PhotoButton() {
inputViewModel.onImageChange(it)
}
}
}
}
class InputViewModel : ViewModel() {
private val _image: MutableLiveData<String> = MutableLiveData("")
val image: LiveData<String> = _image
fun onImageChange(newImage: String) {
_image.value = newImage
}
}
PhotoButton.kt
@Composable
fun PhotoButton(onValChange: ((String) -> Unit)?){
val context = LocalContext.current
val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val file = File(storageDir, "picFromCamera")
val uri = FileProvider.getUriForFile(
context,
context.packageName.toString() ".provider",
file
)
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
if (onValChange != null) {
onValChange(uri.toString())
}
}
FAB() {
launcher.launch(uri)
}
}
CodePudding user response:
You're creating a new view model on each recomposition:
val inputViewModel = InputViewModel()
Instead you should use viewModel()
: it'll create a new view model on the first call, and store it for the future calls:
val inputViewModel = viewModel<InputViewModel>()
Check out more about view models usage in compose state documentation.