深入理解Kotlin协程
上QQ阅读APP看书,第一时间看更新

1.2.3 取消响应

异步任务如果不加任何约束,就像放出去的小狗,如果它玩够了,就会自己回来。但也有很多情况下我们希望它能提前回来,这种情况就只能出去找了,当然,还不一定找得到。所以异步任务必须要像风筝一样,在需要的时候能够由外部主动收回。

对于前面的例子,最简单的改法就是将thread函数创建的Thread实例返回,在download函数中不断检查线程的中断标志来实现任务的取消响应。如代码清单1-10所示。

代码清单1-10 取消异步调用


fun asyncBitmapCancellable(
  url: String, onSuccess: (Bitmap) -> Unit,
  onError: (Throwable) -> Unit
) = thread {
  try {
    downloadCancellable(url).also(onSuccess)
  } catch (e: Exception) {
    onError(e)
  }
}

fun downloadCancellable(url: String): Bitmap {
  return getAsStream(url).use { inputStream ->
    val bos = ByteArrayOutputStream()
    val buffer = ByteArray(1024)
    while (true) {
      ... 
      if (Thread.interrupted()) 
        throw InterruptedException("Task is cancelled.")
    }
    bos.toByteArray()
  }
}

如果需要取消任务,调用asyncBitmapCancellable返回的线程的interrupt函数即可。

请注意,取消响应中的响应是很关键的一点,需要异步任务主动配合取消,如果它不配合,那么外部也就没有办法,只能听之任之了。这时的异步任务颇有断线风筝的意思,能否回来只能看风筝自己的“心情”了。

注意 JDK最初提供了停止线程的API,但它很快就被废弃了,因为强行停止一个线程会导致该线程中持有的资源无法正常释放,进而出现不安全的程序状态。