Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cancel Retrofit request started from ViewModel coroutine job

I would like my app users to be able to cancel file upload.

My coroutine upload job in ViewModel looks like this

private var uploadImageJob: Job? = null
private val _uploadResult = MutableLiveData<Result<Image>>()
val uploadResult: LiveData<Result<Image>>
    get() = _uploadResult

fun uploadImage(filePath: String, listener: ProgressRequestBody.UploadCallbacks) {
    //...
    uploadImageJob = viewModelScope.launch {
        _uploadResult.value = withContext(Dispatchers.IO) {
            repository.uploadImage(filePart)
        }
    }
}

fun cancelImageUpload() {
    uploadImageJob?.cancel()
}

Then in the repository the Retrofit 2 request is handled like this

suspend fun uploadImage(file: MultipartBody.Part): Result<Image> {
    return try {
        val response = webservice.uploadImage(file).awaitResponse()
        if (response.isSuccessful) {
            Result.Success(response.body()!!)
        } else {
            Result.Error(response.message(), null)
        }
    } catch (e: Exception) {
        Result.Error(e.message.orEmpty(), e)
    }
}

When cancelImageUpload() it called the job gets cancelled and the exception gets caught in the repository but the result won't get assigned to uploadResult.value.

Any ideas please how to make this work?

PS: There is a similar question Cancel file upload (retrofit) started from coroutine kotlin android but it suggests using coroutines call adapter which is depricated now.

like image 880
yaugenka Avatar asked Jan 11 '20 11:01

yaugenka


People also ask

How do I cancel a Coroutine job?

cancelAndJoin() // cancels the job and waits for its completion println("main: Now I can quit.") like the following example shows: val startTime = System. currentTimeMillis() val job = launch(Dispatchers.


1 Answers

Have finally managed to make it work by moving withContext one level up like this

uploadImageJob = viewModelScope.launch {
    withContext(Dispatchers.IO) {
        _uploadResult.postValue(repository.uploadImage(filePart))
    }
}
like image 104
yaugenka Avatar answered Oct 19 '22 19:10

yaugenka