https://kotlinlang.org logo
c

Chethan

10/29/2020, 12:10 PM
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 ?
Copy code
viewModel.uploadImage(ContextAmbient.current, job, uri).observeAsState()
Copy code
@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)
            }
        }
    }
}
g

Grigorii Yurkov

10/29/2020, 12:15 PM
I think, you need
LaunchedTask
function
But you need to move
LiveData
to the view model's property (
uploadImage
should return
Unit
)
c

Chethan

10/29/2020, 1:56 PM
@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 .
g

Grigorii Yurkov

10/29/2020, 2:05 PM
Ok I would create
ImageUploader
class with single
LiveData
as property and
upload
as function.
Copy code
@Composable
fun MyFunction()  {
   val uploader = remember { ImageUploder.create(uri) }
   LaunchedTask {
      uploader.upload()
   }
   uploader.livedata.observeAsState()
}
z

Zach Klippenstein (he/him) [MOD]

10/29/2020, 2:06 PM
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
2
j

Joost Klitsie

10/29/2020, 2:43 PM
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.
Copy code
data class ViewState(
	val images: List<ImageViewState>
)

data class ImageViewState(
	val uri: Uri // or whatever,
	val showLoading: Boolean,
	val showRetry: Boolean
)
Then your code:
Copy 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
1
c

Chethan

10/30/2020, 1:05 AM
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
👍 2
2 Views