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

1.2.4 复杂分支

我们可以为同步的逻辑添加分支甚至循环操作,但对于异步的逻辑而言,想要做到这一点就相对困难了,如代码清单1-11所示。

代码清单1-11 同步循环


val bitmaps = urls.map { syncBitmap(it) }

调用syncBitmap可以同步获取一个Bitmap实例,并且很容易就能写出批量同步获取多个Bitmap实例的逻辑,如代码清单1-11所示。我们甚至还可以很方便地用一个try...catch来捕获这其中出现的所有异常。

而对于asyncBitmap而言呢?由于需要将所有的结果整合起来,因此我们还需要用到一些同步工具,见代码清单1-12。

代码清单1-12 异步循环


val countDownLatch = CountDownLatch(urls.size)
val map = urls.map { it to EMPTY_BITMAP }
  .toMap(ConcurrentHashMap<String, Bitmap>())
urls.map { url ->
  asyncBitmap(url, onSuccess = {
    map[url] = it
    countDownLatch.countDown() // ... ②
  }, onError = {
    showError(it)
    countDownLatch.countDown() //... ③
  })
}
countDownLatch.await() //... ①
val bitmaps = map.values

这段程序会在①的位置阻塞,直到所有回调的②或③位置执行之后才会继续执行。程序的执行流程如图1-6所示。

图1-6 异步循环结果映射

如果大家不熟悉CountDownLatch,一时间可能很难明白这段代码的执行流程。没关系,我们知道它很复杂就够了。

提示 EMPTY_BITMAP是一个空的Bitmap对象,用来充当空对象。这样做是因为ConcurrentHashMap中的value不能为null。