How do I cancel a kotlin coroutine for a blocking download operation
Asked Answered
T

1

2

Here is the piece of code I have running on Dispatcher.IO thread pool

suspend fun download(rquest: YoutubleDLRequest){
      withContext(Dispatchers.IO){
         YoutubeDL.init().execute(request) // downloads media in background
      }
   }

Now, when user clicks a button, the download starts - it either fails due to network error, or completes. My question is how do I cancel this download operation? I have another button to allow the user to cancel the download operation. If I wrap withContext in a launch and keep a reference to the job and then try to cancel the job on the button click, it will not work. I know, I need another suspension point, I tried calling another suspend function with yield inside a while loop. But, the while loop does not let the download code execute at all. I don't understand, how cancel would be implemented in this scenario. Any help would be appreciated.

Trabeated answered 13/4, 2021 at 5:54 Comment(0)
B
0

This answer was written before the original poster changed his question, and is therefore not on point anymore. Sorry.


There are multiple options you could consider, depending on your usecase:

Let's assume your YoutubeDownloader throws a DownloadException when it is canceled:

suspend fun download(rquest: YoutubleDLRequest){
    withContext(Dispatchers.IO){
        try{
            YoutubeDL.init().execute(request) // downloads media in background
            Log.d("myTag", "Success"
        } catch ( e: DownloadException){
            Log.e("myTag", "Download-Failure: $e")   
        }
    }
 }

In case you'd like to actively cancel the coroutine, you could save it as a variable, like here in the basic-docs, with more examples here in the cancellation docs:

val myDownloadJob = withContext(Dispatchers.IO){ /* your code here */}

val myDownloadJob = someScope.launch(someDispatcher){ /* your code here */ } 

// somewhere else:
myDownloadJob.cancel()
Birgit answered 13/4, 2021 at 6:23 Comment(4)
withContext() does not return a Job instance, nevertheless, if I wrap the withContext call in a launch builder, I can get a job, but cancelling such an operation is complex, as youtube-dl is a wrapper around a python library, the code being executed is not java code. I have tried the cancelling solutions described in the documentation, however, they don't seem to solve my problem.Trabeated
Sorry for that mistake, i haven't had a coffee yet.. I updated my code.Birgit
> I have tried the cancelling solutions described in the documentation, however, they don't seem to solve my problem. --> did you look into the python lib docs or coroutine docs? I guess you will have to write gluecode like if(coroutineCanceled) then (call cancel on the python lib)Birgit
I figured it out, my android process started a python process when downloading the media. For cancellation, I query for the pid of the python process on the click of cancel button, then the pid is passed to android's Process.killProccess static method, it kills the python process, thus stopping the download. I think the problem is resolved, it is not possible to stop download action from normal java/kotlin code without killing the app process itself. So, it is not a coroutine issue.Trabeated

© 2022 - 2024 — McMap. All rights reserved.