改为异步 新建async包
新建AsyncTask.kt
package com.yzdzy.kotlin.chapter7.async
import java.util.concurrent.Executors
//线程池
private val pool by lazy {
Executors.newCachedThreadPool()
}
class AsyncTask(val block: () -> Unit) {
fun execute() = pool.execute(block)
}
修改BaseCoroutines.kt
package com.yzdzy.kotlin.chapter7.basic
import cn.kotliner.coroutine.common.HttpError
import cn.kotliner.coroutine.common.HttpException
import cn.kotliner.coroutine.common.HttpService
import cn.kotliner.coroutine.common.log
import cn.kotliner.coroutine.ui.LOGO_URL
import com.yzdzy.kotlin.chapter7.async.AsyncTask
import java.lang.Exception
import javax.xml.ws.http.HTTPException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.startCoroutine
import kotlin.coroutines.suspendCoroutine
fun 我要开始协程了(block: suspend () -> Unit) {
block.startCoroutine(BaseCoroutines())
}
suspend fun 我要开始加载图片了(url: String) = suspendCoroutine<ByteArray> { continuation ->
AsyncTask {
log("耗时下载图片")
try {
val reponseBody = HttpService.service.getLogo(LOGO_URL).execute()
if (reponseBody.isSuccessful) {
reponseBody.body()?.byteStream()?.readBytes()?.let(continuation::resume)
} else {
continuation.resumeWithException(HttpException(reponseBody.code()))
}
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}.execute()
}
运行看log
异步已经完成了。
但是main setLogo应该在主线程执行。而不是子线程。。如何操作呢
继续修改BaseCoroutines.kt 下面的第一段代码是讲如何切换到ui线程 第二段是整个BaseCoroutines.kt
//切换ui线程
SwingUtilities.invokeLater{
continuation.resumeWithException(HttpException(reponseBody.code()))
}
package com.yzdzy.kotlin.chapter7.basic
import cn.kotliner.coroutine.common.HttpError
import cn.kotliner.coroutine.common.HttpException
import cn.kotliner.coroutine.common.HttpService
import cn.kotliner.coroutine.common.log
import cn.kotliner.coroutine.ui.LOGO_URL
import com.yzdzy.kotlin.chapter7.async.AsyncTask
import java.lang.Exception
import javax.swing.SwingUtilities
import javax.xml.ws.http.HTTPException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.startCoroutine
import kotlin.coroutines.suspendCoroutine
fun 我要开始协程了(block: suspend () -> Unit) {
block.startCoroutine(BaseCoroutines())
}
suspend fun 我要开始加载图片了(url: String) = suspendCoroutine<ByteArray> { continuation ->
AsyncTask {
log("耗时下载图片")
try {
val reponseBody = HttpService.service.getLogo(LOGO_URL).execute()
if (reponseBody.isSuccessful) {
reponseBody.body()?.byteStream()?.readBytes()?.let{
//切换ui线程
SwingUtilities.invokeLater{
continuation.resume(it)
}
}
} else {
//切换ui线程
SwingUtilities.invokeLater{
continuation.resumeWithException(HttpException(reponseBody.code()))
}
}
} catch (e: Exception) {
SwingUtilities.invokeLater{
continuation.resumeWithException(e)
}
}
}.execute()
}
可以看到上面用了三次的
SwingUtilities.invokeLater{
为了简化
继续在 async 包中新建 UiCotinuationWrapper.kt
package com.yzdzy.kotlin.chapter7.async
import javax.swing.SwingUtilities
import kotlin.coroutines.Continuation
/**
* Created by benny on 5/29/17.
*/
class UiCotinuationWrapper<T>(val continuation: Continuation<T>): Continuation<T>{
override val context = continuation.context
override fun resumeWith(result: Result<T>) {
SwingUtilities.invokeLater { continuation.resumeWith(result) }
}
}
BaseCoroutines.kt 就可以写成
package com.yzdzy.kotlin.chapter7.basic
import cn.kotliner.coroutine.common.HttpException
import cn.kotliner.coroutine.common.HttpService
import cn.kotliner.coroutine.common.log
import cn.kotliner.coroutine.ui.LOGO_URL
import com.yzdzy.kotlin.chapter7.async.AsyncTask
import com.yzdzy.kotlin.chapter7.async.UiCotinuationWrapper
import java.lang.Exception
import javax.swing.SwingUtilities
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.startCoroutine
import kotlin.coroutines.suspendCoroutine
fun 我要开始协程了(block: suspend () -> Unit) {
block.startCoroutine(BaseCoroutines())
}
suspend fun 我要开始加载图片了(url: String) = suspendCoroutine<ByteArray> { continuation ->
AsyncTask {
val uiCotinuationWrapper = UiCotinuationWrapper(continuation)
log("耗时下载图片")
try {
val reponseBody = HttpService.service.getLogo(LOGO_URL).execute()
if (reponseBody.isSuccessful) {
reponseBody.body()?.byteStream()?.readBytes()?.let {
//切换ui线程
uiCotinuationWrapper.resume(it)
}
} else {
//切换ui线程
uiCotinuationWrapper.resumeWithException(HttpException(reponseBody.code()))
}
} catch (e: Exception) {
uiCotinuationWrapper.resumeWithException(e)
}
}.execute()
}
运行下效果不变
但是仍然定义了 val uiCotinuationWrapper = UiCotinuationWrapper(continuation)
然后再使用 uiCotinuationWrapper 调用其他方法 感觉仍然不方便
啊哦 上面log错了一个地方 这个地方改一下
package cn.kotliner.coroutine.ui
import cn.kotliner.coroutine.common.HttpError
import cn.kotliner.coroutine.common.HttpService
import cn.kotliner.coroutine.common.log
import com.yzdzy.kotlin.chapter7.async.AsyncTask
import com.yzdzy.kotlin.chapter7.basic.我要开始加载图片了
import com.yzdzy.kotlin.chapter7.basic.我要开始协程了
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.HttpException
import retrofit2.Response
import javax.swing.JFrame.EXIT_ON_CLOSE
import javax.swing.SwingUtilities
/**
* Created by benny on 5/20/17.
*/
const val LOGO_URL = "http://www.imooc.com/static/img/index/logo.png?t=1.1"
fun main(args: Array<String>) {
val frame = MainWindow()
frame.title = "Coroutine@Bennyhuo"
frame.setSize(200, 150)
frame.isResizable = true
frame.defaultCloseOperation = EXIT_ON_CLOSE
frame.init()
frame.isVisible = true
frame.onButtonClick {
log("协程之前")
我要开始协程了 {
log("协程开始")
val imageDate = 我要开始加载图片了(LOGO_URL)
log("拿到图片")
frame.setLogo(imageDate)
}
log("协程之后")
}
}
就是
log("协程之后")
的位置错了
继续刚才不方便的问题。这次通过拦截器实现
在async包中新建 AsyncContext.kt
package com.yzdzy.kotlin.chapter7.async
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.Continuation
import kotlin.coroutines.ContinuationInterceptor
class AsyncContext :AbstractCoroutineContextElement(ContinuationInterceptor),ContinuationInterceptor{
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> {
return UiCotinuationWrapper(continuation.context.fold(continuation){
continuation, element ->
if(element!=this&&element is ContinuationInterceptor){
element.interceptContinuation(continuation)
}else continuation
})
}
}
修改Corutines.kt
package com.yzdzy.kotlin.chapter7.basic
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
class BaseCoroutines(val content: CoroutineContext = EmptyCoroutineContext) : Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: Result<Unit>) {
}
}
修改BaseCoroutines.kt
package com.yzdzy.kotlin.chapter7.basic
import cn.kotliner.coroutine.common.HttpException
import cn.kotliner.coroutine.common.HttpService
import cn.kotliner.coroutine.common.log
import cn.kotliner.coroutine.ui.LOGO_URL
import com.yzdzy.kotlin.chapter7.async.AsyncContext
import com.yzdzy.kotlin.chapter7.async.AsyncTask
import com.yzdzy.kotlin.chapter7.async.UiCotinuationWrapper
import java.lang.Exception
import javax.swing.SwingUtilities
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.startCoroutine
import kotlin.coroutines.suspendCoroutine
fun 我要开始协程了(block: suspend () -> Unit) {
block.startCoroutine(BaseCoroutines(AsyncContext() ))
}
suspend fun 我要开始加载图片了(url: String) = suspendCoroutine<ByteArray> { continuation ->
AsyncTask {
log("耗时下载图片")
try {
val reponseBody = HttpService.service.getLogo(LOGO_URL).execute()
if (reponseBody.isSuccessful) {
reponseBody.body()?.byteStream()?.readBytes()?.let {
//切换ui线程
continuation.resume(it)
}
} else {
//切换ui线程
continuation.resumeWithException(HttpException(reponseBody.code()))
}
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}.execute()
}
运行看效果
完美
还可以接续优化 把异步部分提取处理啊
修改BaseCoroutines.kt
package com.yzdzy.kotlin.chapter7.basic
import cn.kotliner.coroutine.common.HttpError
import cn.kotliner.coroutine.common.HttpException
import cn.kotliner.coroutine.common.HttpService
import cn.kotliner.coroutine.common.log
import cn.kotliner.coroutine.ui.LOGO_URL
import com.yzdzy.kotlin.chapter7.async.AsyncContext
import com.yzdzy.kotlin.chapter7.async.AsyncTask
import com.yzdzy.kotlin.chapter7.async.UiCotinuationWrapper
import java.lang.Exception
import javax.swing.SwingUtilities
import kotlin.coroutines.*
fun 我要开始协程了(block: suspend () -> Unit) {
block.startCoroutine(BaseCoroutines(AsyncContext()))
}
suspend fun <T> 我要开始耗时操作了(block: () -> T) = suspendCoroutine<T> { continuation ->
AsyncTask {
log("异步操作开始前")
try {
continuation.resume(block())
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}.execute()
}
fun 我要开始加载图片了(url: String): ByteArray {
log("下载图片开始")
val reponseBody = HttpService.service.getLogo(url).execute()
if (reponseBody.isSuccessful) {
reponseBody.body()?.byteStream()?.readBytes()?.let {
return it
}
throw HttpException(HttpError.HTTP_ERROR_NO_DATA)
} else {
//切换ui线程
throw HttpException(reponseBody.code())
}
}
修改main
package cn.kotliner.coroutine.ui
import cn.kotliner.coroutine.common.HttpError
import cn.kotliner.coroutine.common.HttpService
import cn.kotliner.coroutine.common.log
import com.yzdzy.kotlin.chapter7.async.AsyncTask
import com.yzdzy.kotlin.chapter7.basic.我要开始加载图片了
import com.yzdzy.kotlin.chapter7.basic.我要开始协程了
import com.yzdzy.kotlin.chapter7.basic.我要开始耗时操作了
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.HttpException
import retrofit2.Response
import javax.swing.JFrame.EXIT_ON_CLOSE
import javax.swing.SwingUtilities
/**
* Created by benny on 5/20/17.
*/
const val LOGO_URL = "http://www.imooc.com/static/img/index/logo.png?t=1.1"
fun main(args: Array<String>) {
val frame = MainWindow()
frame.title = "Coroutine@Bennyhuo"
frame.setSize(200, 150)
frame.isResizable = true
frame.defaultCloseOperation = EXIT_ON_CLOSE
frame.init()
frame.isVisible = true
frame.onButtonClick {
log("协程之前")
我要开始协程了 {
log("协程开始")
val imageDate = 我要开始耗时操作了 {
我要开始加载图片了(LOGO_URL)
}
log("拿到图片")
frame.setLogo(imageDate)
}
log("协程之后")
}
}
效果不变