Home > Back-end >  Get image from Uri and show in composable with ViewModel
Get image from Uri and show in composable with ViewModel

Time:10-05

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.

  • Related