android线程与协程

2020-08-19  本文已影响0人  钊神归来
1.线程就是线程,
2.协程本质就是一种线程框架,仅仅是针对Java中的Thread做了一次更友好的封装。让我们更方便的使用Java中的线程才是Kotlin-JVM中协程的真正目的。

本质上和Handler,AsyncTask,RxJava 基本是一致的。只不过Kotlin中的协程对于切换线程比他们更方便一些。这其中最核心的是suspend这个Kotlin协程中的关键字。suspend就是挂起的意思,挂起就是切换线程 没其他作用,最多就是切到其他线程以后还可以自动切回来,避免过多的callback,
所有被suspend标记的函数 要么在协程里被调用,要么在其他挂起函数里被调用,否则就无法实现 切走以后又可以切回来的效果

class MainActivity : AppCompatActivity() {
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        GlobalScope.launch(Dispatchers.Main) {
            getInfo()
            getInfoNoContext()
            Log.v("wuyue", "我又切回来了 in thread " + Thread.currentThread().name)
        }
    }
  
    /**
     * 挂起就是切换线程 没其他作用,最多就是切到其他线程以后还可以自动切回来,避免过多的callback
     * 所有被suspend标记的函数 要么在协程里被调用,要么在其他挂起函数里被调用,否则就无法实现
     * 切走以后又可以切回来的效果
     */
    suspend fun getInfo() {
        /**
         * withContext挂起函数 内部实现了挂起的流程,suspend其实并没有这个功能
         * kotlin中有很多挂起函数,withContext 应该是最常用的
         */
        withContext(Dispatchers.IO) {
            Log.v("wuyue", "getInfo in thread " + Thread.currentThread().name)
        }
    }
  
    /**
     * 这个函数 虽然用suspend标记 但是并没有 用withContext 指定挂起,
     * 所以是没办法实现切线程的作用的,自然而然也就无法实现 所谓的挂起了
     * 个人理解这个suspend关键字的作用就是提醒 调用者注意 你如果调用的是一个被suspend标记的函数
     * 那么一定要注意 这个函数可能是一个后台任务,是一个耗时的操作,你需要在一个协程里使用他。
     * 如果不在协程里使用,那么kotlin的编译 就会直接报错了。
     *
     *
     * 这点其实对于android来讲还是很有用的,你所有认为耗时的操作都可以用suspend来标记,然后在内部指定
     * 这个协程的thread 为 io thread, 如果调用者没有用launch来 call 这个方法,那么编译就报错。
     * 自然而然就避免了很多 主线程操作io的问题
     *
     */
    suspend fun getInfoNoContext() {
        Log.v("wuyue", "getInfoNoContext in thread " + Thread.currentThread().name)
    }
  
}

这段代码很简单,可以多看一下注释。很多人都会被所谓Kotlin协程的非阻塞式吓到,其实你就理解成Kotlin中所宣传的非阻塞式,无非是用阻塞的写法来完成非阻塞的任务而已。

试想一下,我们上述Kotlin中的代码 如果用Thread来写,就会比较麻烦了,甚至还需要用到回调(如果你不用handler的话)。这一点上Kotlin 协程的作用和RxJava其实是一致的,只不过Kotlin做的更彻底,比RxJava更优雅更方便更简洁。

考虑一种稍微复杂的场景,某个页面需要2个接口都返回以后才能刷新展示,此种需求,如果用原生的Java concurrent并发包是可以做的,但是比较麻烦,要考虑各种异常带来的问题。

比较好的实现方式是用RxJava的zip操作符来做,在有了Kotlin以后,如果利用Kotlin,这段代码甚至会比zip操作符还要简单。例如:

class MainActivity : AppCompatActivity() {
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        GlobalScope.launch(Dispatchers.Main) {
            Log.v("wuyue", "time 1==" + System.currentTimeMillis())
                val requestA = async { requestA() }
                val requestB = async { requestB() }
               val sum = requestA.await() +"_____" +requestB.await()
               Log.v("wuyue", "time 2==" + System.currentTimeMillis() + " get sum=" + sum)
        }
    }
  
    /**
     * 3s以后 才拿到请求结果 IQOO
     */
   suspend fun requestA(): String {
        delay(3 * 1000)
        Log.v("wuyue", "requestA in " + Thread.currentThread().name)
        return "IQOO"
    }
  
    /**
     * 5秒以后拿到请求结果 B
     */
    suspend requestB(): String {
        delay(5 * 1000)
        Log.v("wuyue", "requestB in " + Thread.currentThread().name)
        return "X27"
    }
  
}
总结:

1、Kotlin-JVM中所谓的协程是假协程,本质上还是一套基于原生Java Thread API 的封装。
2、Kotlin-JVM中所谓的协程挂起,就是开启了一个子线程去执行任务,并且可以自动切回原来的线程
3、Kotlin-JVM中的协程最大的价值是写起来比RxJava的线程切换还要方便。几乎就是用阻塞的写法来完成非
阻塞的任务

上一篇下一篇

猜你喜欢

热点阅读