美文网首页
android线程与协程

android线程与协程

作者: 钊神归来 | 来源:发表于2020-08-19 17:10 被阅读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的线程切换还要方便。几乎就是用阻塞的写法来完成非
    阻塞的任务

    相关文章

      网友评论

          本文标题:android线程与协程

          本文链接:https://www.haomeiwen.com/subject/ihmcjktx.html