Thread
#compose
    Chethan

    Chethan

    1 year ago
    How can I avoid network call on every recomposes , I have situation where I subscribe to MediatorLive data with saying observeAsState(). Now every time recompose, It goes and call the same network call and takes infinite loop. here is the use case - I pick the images from the gallery, every image will play linearprogress bar (multipart upload) , I have used MediatorLive data to listen two values - percentage of chunks it is sending and also to listen the final response from the server. Now the problem I have is, this particular line inside compose method calls the network for every recompose, since the network call is managed inside uploadImage, it goes end less, How can I avoid this ?
    viewModel.uploadImage(ContextAmbient.current, job, uri).observeAsState()
    @Composable
    fun SetImageUpdateProgressBar(
        job: Job,
        uri: Uri,
        viewModel: UploadViewModel = viewModel()
    ) {
    
        var result = viewModel.uploadImage(ContextAmbient.current, job, uri).observeAsState()
        result?.value?.let { data ->
    
            when (data.response.status) {
    
                Status.ERROR -> {
                    // setRetryButton()
                }
    
                Status.SUCCESS -> {
                    ShowProgressBar(value = 0, visibility = false)
                }
    
                Status.LOADING -> {
                    ShowProgressBar(data.uploadProgressValue)
                }
            }
        }
    }
    Grigorii Yurkov

    Grigorii Yurkov

    1 year ago
    I think, you need
    LaunchedTask
    function
    But you need to move
    LiveData
    to the view model's property (
    uploadImage
    should return
    Unit
    )
    Chethan

    Chethan

    1 year ago
    @Grigorii Yurkov If I make LiveData to be View model property then that going to be single property to all the image uploads , all the subsequent uploads refer common property .
    Grigorii Yurkov

    Grigorii Yurkov

    1 year ago
    Ok I would create
    ImageUploader
    class with single
    LiveData
    as property and
    upload
    as function.
    @Composable
    fun MyFunction()  {
       val uploader = remember { ImageUploder.create(uri) }
       LaunchedTask {
          uploader.upload()
       }
       uploader.livedata.observeAsState()
    }
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    I'd recommend reading this article to see why doing side effects directly in composition is bad: https://developer.android.com/jetpack/compose/mental-model
    j

    Joost Klitsie

    1 year ago
    Why not have your model have a view state object, that has a list of objects that can have loading states and whatnot? You press one, that item in the list will go into loading state, you observe on that list anyway.
    data class ViewState(
    	val images: List<ImageViewState>
    )
    
    data class ImageViewState(
    	val uri: Uri // or whatever,
    	val showLoading: Boolean,
    	val showRetry: Boolean
    )
    Then your code:
    @Composable
    fun composeTheStuff() {
    	val viewState by viewModel.viewState.observeAsState()
    	viewState.images.foreach { imageViewState ->
    		imageInGrid(imageViewState, viewModel)
    	}
    }
    
    @Composable
    fun imageInGrid(imageViewState: ImageViewState, viewModel) {
    	Box {
    		Image(modifier= Modifier.onClick({viewModel.uploadImage(imageViewState.uri)}))
    		AnimatedVisibility(show = imageViewState.showLoading) {
    			//.. loading state
    		}
    		AnimatedVisibility(show = imageViewState.showRetry) {
    			//.. retry state
    		}
    	}
    }
    I mean its highly pseudo code, but I don't see why you trigger an upload from the composable instead of having the viewmodel take care of that and just give a new state to the view
    Chethan

    Chethan

    1 year ago
    Where do you think I should call when user is selecting image from gallery ? how do you handover to view model from view?, somewhere you have to call from the view to view model method, isn’t ? trigger should happen from the composable function. My scenario is to load selected image to remote without any intervention, ie, user will not click to upload, as soon as he picked up from the gallery will start uploading it to remote.
    Hi @Grigorii Yurkov, Your approach helped here. I have created separate viewmodel with livedata as property , within that I have upload function which doesn’t return anything but it updates livedata property of the same view model . since it is segregated out of the main view model and having dedicated livedata property , every image updates can be captured concurrently