Cancel Retrofit request started from ViewModel coroutine job
Asked Answered
H

1

8

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.

Hydric answered 11/1, 2020 at 11:57 Comment(0)
H
7

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))
    }
}
Hydric answered 11/1, 2020 at 22:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.