kotlin协程-Android实战

// observer(观察者)个数有0到1时执行
// 即第一次调用observe或observeForever时执行
override fun onActive() {
super.onActive()
// 启动协程并执行协程体
blockRunner?.maybeRun()
}

// observer(观察者)个数有1到0时执行
// 即调用removeObserver时触发检查并执行回调
override fun onInactive() {
super.onInactive()
// 取消协程
blockRunner?.cancel()
}
}

可见CoroutineLiveData是在onActive()启动协程,在onInactive()取消协程

所以使用LiveData对协程的支持, 那么CoroutineActivity Demo的代码写法如下

class CoroutineActivity : AppCompatActivity() {
private lateinit var testApi: TestApi

fun requestData1() {
liveData {
try {
val lastedNews = testApi.getLatestNews2()
emit(lastedNews.stories!![0].title!!)
} catch(e: Exception) {
emit(“error”)
}
}.observe(this, Observer {
tv_text.text = it
})
}
}

上面我们讲了协程在android里最常用的用法,下面将介绍协程的一些基本知识

协程上下文

协程上下文用CoroutineContext表示,kotlin中 比较常用的Job协程调度器(CoroutineDispatcher)协程拦截器(ContinuationInterceptor)等都是CoroutineContext的子类,即它们都是协程上下文

先看一下CoroutineContext 比较重要的plus方法,它是一个用operator修复的重载(+)号的操作符方法

@SinceKotlin(“1.3”)
public interface CoroutineContext {

/**

  • Returns a context containing elements from this context and elements from other [context].
  • The elements from this context with the same key as in the other one are dropped.
    */
    public operator fun plus(context: CoroutineContext): CoroutineContext =
    if (context === EmptyCoroutineContext) this else // fast path – avoid lambda creation
    context.fold(this) { acc, element ->
    val removed = acc.minusKey(element.key)
    if (removed === EmptyCoroutineContext) element else {
    // make sure interceptor is always last in the context (and thus is fast to get when present)
    val interceptor = removed[ContinuationInterceptor]
    if (interceptor == null) CombinedContext(removed, element) else {
    val left = removed.minusKey(ContinuationInterceptor)
    if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else
    CombinedContext(CombinedContext(left, element), interceptor)
    }
    }
    }
    }

比如上面说的MainScope定义就使用了+号操作符

public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)

如果你看启动协程的源码就会发现,在kotlin中 大量使用 + 号操作符,所以kotlin中大部分CoroutineContext对象都是CombinedContext对象

上面的example使用的launch方法启动协程有三个参数, 分别是协程上下文协程启动模式协程体

public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext, // 协程上下文
start: CoroutineStart = CoroutineStart.DEFAULT, // 协程启动模式
block: suspend CoroutineScope.() -> Unit // 协程体
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}

协程启动模式

  • DEFAULT

立即执行协程体

runBlocking {
val job = GlobalScope.launch(start = CoroutineStart.DEFAULT) {
println("1: " + Thread.currentThread().name)
}
// 不需要调用join方法
// job.join()
}

打印结果

1: DefaultDispatcher-worker-1

CoroutineStart.DEFAULT启动模式不需要手动调用joinstart等方法,而是在调用launch方法的时候就会自动执行协程体的代码

  • LAZY

只有在需要的情况下才执行协程体

runBlocking {
val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
println("1: " + Thread.currentThread().name)
}
// 一定调用join方法
job.join()
}

打印结果

1: DefaultDispatcher-worker-1

CoroutineStart.LAZY启动模式一定要手动调用joinstart等方法,否者协程体不会执行

  • ATOMIC

立即执行协程体,但在开始运行之前无法取消, 即开启协程会无视cancelling状态

runBlocking {
val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
println("1: " + Thread.currentThread().name)
delay(1000)
println("2: " + Thread.currentThread().name)
}
job.cancel()
delay(2000)
}

打印结果

1: DefaultDispatcher-worker-1

CoroutineStart. ATOMIC启动模式的协程体 即使调了cancel方法 也一定会执行,因为开启协程会无视cancelling状态;上面的example只打印了一句话,是因为执行delay(1000)的时候 发现协程处于关闭状态, 所以出现了JobCancellationException异常,导致下面的代码没有执行,如果 delay(1000) 这句代码用 try catch 捕获一下异常,就会继续执行下面的代码

  • UNDISPATCHED

立即在当前线程执行协程体,直到第一个 suspend 调用 挂起之后的执行线程取决于上下文当中的调度器了

runBlocking {
println("0: " + Thread.currentThread().name)
// 注意这里没有用GlobalScope.launch
// 因为GlobalScope.launch启动的是一个顶层协程, 无法关联当前协程的上下文(coroutineContext), 导致结果有偏差
launch(context = Dispatchers.Default, start = CoroutineStart.UNDISPATCHED) {
println("1: " + Thread.currentThread().name)
delay(1000)
println("2: " + Thread.currentThread().name)
}
delay(2000)
}

打印结果

0: main
1: main
2: DefaultDispatche

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值