How to perform an async task for every item in a for loop?

Viewed 63

I have a list of urls in a mutable list and I want to perform an IO operation, cacheVideo on each of the urls sequentially one after the other

suspend fun cacheVideo(mediaItem: MediaItem) = {
    val videoUrl = mediaItem.mediaUrl
    val uri = Uri.parse(videoUrl)
    val dataSpec = DataSpec(uri)

    val progressListener =
        CacheUtil.ProgressListener { requestLength, bytesCached, newBytesCached ->

            val downloadPercentage: Double = (bytesCached * 100.0
                    / requestLength)
            
            if (downloadPercentage == 100.0) {
                // I WANT TO RETURN HERE
            }
        }

    try {
        CacheUtil.cache(
            dataSpec,
            cache,
            DataSourceFactory?.createDataSource(),
            progressListener,
            null
        );
    } catch (err: Exception) {
        // IF ERROR, THEN RETURN NULL
    }
}

How would I shape the cacheVideo to do that using Coroutines?

uiScope.launch {
 for(item in mediaItems){
  cacheVideo(item) // I WANT TO WAIT HERE BEFORE GOING TO NEXT ITEM
 }
}
1 Answers

You can use suspendCancellableCoroutine to wait for the progress:

suspend fun cacheVideo(mediaItem: MediaItem) = suspendCancellableCoroutine { continuation ->
    val videoUrl = mediaItem.mediaUrl
    val uri = Uri.parse(videoUrl)
    val dataSpec = DataSpec(uri)

    val progressListener =
        CacheUtil.ProgressListener { requestLength, bytesCached, newBytesCached ->

            val downloadPercentage: Double = (bytesCached * 100.0
                    / requestLength)
            
            if (downloadPercentage == 100.0) {
                continuation.resume() // resumes the execution of the corresponding coroutine 
            }
        }

//  continuation.invokeOnCancellation {
//      // clear some resources, cancel tasks, close streams etc if need.
//  }

    try {
        CacheUtil.cache(
            dataSpec,
            cache,
            DataSourceFactory?.createDataSource(),
            progressListener,
            null
        );
    } catch (err: Exception) {
        continuation.resume() // resumes the execution of the corresponding coroutine 
    }
}
Related