协程是什么
协程是一种轻量级的异步编程方式,允许用户编写看似同步实则异步的代码。
协程的本质
协程的本质是一种语法糖,他的出现是用来解决异步问题,但是本身却并不提供异步的能力。
协程是编译器级别的,切换有程序控制,而线程是系统级别的,线程的切换由操作系统控制。
协程的优点
1.轻量级,占用资源更少。
2.避免”回调地狱“
3.挂起不影响线程的其他任务
CoroutineScope和Job
CoroutineScope 协程的的作用范围,每个CoroutineScope都有一个主job,之后所有的launch调用都是创建一个子job。
每个子job都有自己的状态,isCompleted(),isActive(),isCanceled()等,还有一些基础操作,如start(),join(),cancel()等。
子job异常会导致自己结束,不会影响父job,但是父job一场,所有的子job都会停止运行。
launch方法
launch方法有个三个参数,CoroutineContext,CoroutineStart,代码块。
CoroutineContext的本质是一个自定义了获取(get),折叠(fold),组合(plus)等的Element集合。
CoroutineStart标识是否立即执行还是延迟启动。
suspend,delay和runBlocking
delay()函数是协程提供的非阻塞方法,suspend关键字修饰,suspend是协程的内置关键字。
suspend关键字修饰的方法会挂起协程,但是不会影响当前线程继续执行其他线程。
Thread.sleep是阻塞线程的,在协程中如果需要阻塞线程使用runBlocking。
一种有用的实现
CoUtils供所有人简易使用
object CoUtils {
/**
* 对应于kotlin coroutine的[kotlinx.coroutines.Dispatchers]
*/
enum class Dispatcher {
/** 使用此调度程序可在 Android 主线程上运行协程*/
MAIN,
/** 此调度程序经过了专门优化,适合在主线程之外执行磁盘或网络I/O */
IO,
/** 此调度程序经过了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作*/
DEFAULT
}
/**
* 协程Job的代理,提供部分操作的封装
*/
class JobControllerinternal constructor(private val job: Job) {
fun cancel(reason: String?) {
job.cancel(CancellationException(reason))
}
val isCompleted: Boolean
get() =job.isCompleted
val isActive: Boolean
get() =job.isActive
val isCancelled: Boolean
get() =job.isCancelled
}
/**
* 创建一个协程任务
* @param dispatcher 指定调度器
* @param runnable 任务
* @return a [JobController]
*/
fun launch(dispatcher: Dispatcher, runnable: Runnable): JobController? {
val job = CoWr.launch(dispatcher, runnable)
return JobController(job)
}
/**
* 创建一个协程任务
* @param dispatcher 指定调度器
* @param runnable 任务
* @param delay 延迟,单位ms
* @return a [JobController]
*/
fun launch(dispatcher: Dispatcher, runnable: Runnable, delay: Long): JobController? {
val job = CoWr.launch(dispatcher, runnable, delay)
return JobController(job)
}
/**
* 创建一个协程任务
* @param dispatcher 指定调度器
* @param block 任务
* @param callback 回调
* @return a [JobController]
*/
fun async(dispatcher: Dispatcher, block:() ->T, callback: CoWr.Callback?): JobController? {
val job = CoWr.async(dispatcher, block, callback)
return JobController(job)
}
/**
* 创建一个协程任务
* @param dispatcher 指定调度器
* @param block 任务
* @return a [JobController]
*/
fun async(dispatcher: Dispatcher, block:() ->T): JobController? {
val job = CoWr.async(dispatcher, block, null)
return JobController(job)
}
}
CoWr包装协程内部的CoroutineScope
object CoWr {
private const val TAG ="CoTrace"
private const val TIME_MONITOR =10
private const val ASYNC_TIME_MONITOR =200
interface Callback {
fun callback(result:T?)
}
private val exceptionHandler: CoroutineExceptionHandler =
CoroutineExceptionHandler { ctx, error->
onError(ctx, error)
}
private val ioScope: CoroutineScope =
CoroutineScope(Dispatchers.IO +SupervisorJob() +exceptionHandler + CoroutineName("io"))
private val defaultScope: CoroutineScope =
CoroutineScope(Dispatchers.Default +SupervisorJob() +exceptionHandler + CoroutineName("default"))
private val mainScope: CoroutineScope =
CoroutineScope(Dispatchers.Main +SupervisorJob() +exceptionHandler + CoroutineName("main"))
fun launch(dispatcher: CoUtils.Dispatcher, runnable: java.lang.Runnable): Job {
return launch(dispatcher, runnable, 0)
}
fun launch(dispatcher: CoUtils.Dispatcher, runnable: java.lang.Runnable, delay: Long): Job {
val enqueueTime = SystemClock.elapsedRealtime()
var startExe =0L
var endTime =0L
val job = selectScope(dispatcher).launch {
startExe = SystemClock.elapsedRealtime()
if (delay >0) {
delay(delay)
}
runnable.run()
endTime = SystemClock.elapsedRealtime()
}
job.invokeOnCompletion{
// 执行业务runable,使用的调度器名称,进队时间,在队列里等待时间,执行时间,在协程队列里的总时间
var cost = endTime - startExe
if (cost >TIME_MONITOR) {
Log.i(TAG,"launchDone:" + runnable.javaClass +"," + dispatcher.name +"," + enqueueTime
+"," + (startExe - enqueueTime) +"," + (cost)
+"," + (SystemClock.elapsedRealtime() - enqueueTime))
}
}
return job
}
fun async(dispatcher: CoUtils.Dispatcher, block:() ->T, callback: Callback?): Job {
val enqueueTime = SystemClock.elapsedRealtime()
var startExe =0L
var endTime =0L
var result:T? =null
val job = selectScope(dispatcher).launch {
startExe = SystemClock.elapsedRealtime()
async {
result = block()
callback?.callback(result)
endTime = SystemClock.elapsedRealtime()
}
}
job.invokeOnCompletion{
// 执行业务runable,使用的调度器名称,进队时间,在队列里等待时间,执行时间,在协程队列里的总时间
var cost = endTime - startExe
if (cost >ASYNC_TIME_MONITOR) {
Log.i(TAG,"asyncDone:" + block.javaClass +"," + dispatcher.name +"," + enqueueTime
+"," + (startExe - enqueueTime) +"," + (cost)
+"," + (SystemClock.elapsedRealtime() - enqueueTime))
}
}
return job
}
private fun selectScope(dispatcher: CoUtils.Dispatcher): CoroutineScope =when (dispatcher) {
CoUtils.Dispatcher.MAIN ->mainScope
CoUtils.Dispatcher.IO ->ioScope
CoUtils.Dispatcher.DEFAULT ->defaultScope
}
private fun onError(context: CoroutineContext, error: Throwable) {
throw error
}
}