<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 參考文章 [Kotlin 的協程用力瞥一眼 - 學不會協程?很可能因為你看過的教程都是錯的](https://kaixue.io/kotlin-coroutines-1/) [Kotlin 協程的掛起好神奇好難懂?今天我把它的皮給扒了](https://kaixue.io/kotlin-coroutines-2/) [到底什么是「非阻塞式」掛起?協程真的更輕量級嗎?](https://kaixue.io/kotlin-coroutines-3/) # 初識協程 ## 什么是協程? 協程原本是一個跟線程非常類似的用于處理多任務的概念,但在Kotlin,協程其實就是一套**由Kotlin官方提供的線程API**,就像Java的Executor和Android的AsyncTask,Kotlin協程也對Thread相關的API做了一套封裝,讓我們不用過多關心線程也可以方便地寫出并發操作。 ## 協程的優勢 既然協程類似于Java的Executor和Android的AsyncTask,那還要協程干嘛呢? 協程本質上和那些其他的線程API一樣方便,但是它借助了kotlin的語言優勢,所以它比那些基于Java的方案會更方便一點,最重要的是,它可以用看起來同步的代碼方式來寫出異步代碼,即**非阻塞式掛起**。 協程最基本的功能就是并發,多線程,用協程你可以把任務切到后臺執行。 比如 ~~~kotlin coroutineScope.launch(Dispatchers.IO) { ... } ~~~ ~~~kotlin coroutineScope.launch(Dispatchers.Main) { ... } ~~~ 這種寫法很簡單,但是它并不能算是協程相對于直接使用Thread的優勢,因為Kotlin已經專門添加了一個函數,來簡化對Thread的直接使用,而kotlin協程最大的好處就是你可以把運行在不同線程的代碼寫在同一個代碼塊里 ~~~kotlin coroutineScope.launch(Dispatchers.Main) { // 開始協程:主線程 val token = api.getToken() // 網絡請求:IO 線程(后臺線程) val user = api.getUser(token) // 網絡請求:IO 線程(后臺線程) nameTv.text = user.name // 更新 UI:主線程 } ~~~ 上下兩行代碼線程切走再切回來,這是Java永遠做不到的。不過這個說實話,差別并不大,畢竟我們寫回調早就寫熟練了,即便是回調地獄,對于習慣的人來說倒也還好,畢竟所謂的回調地獄一般也就二三層。但是,這種不大的差別其實也蠻大的,協程改變了并發任務的操作難度。消除了回調,那么多線程協作任務的難度直接就抹平了,沒有了。這其實是質變的,而且這種質變也對我們的開發工作帶來了質變。協程可以讓我們輕松地寫出復雜的并發代碼,而且由于并發代碼變得不難寫,一些本來不可能實現的并發任務變得可能,甚至變得很簡單,這些才是協程的優勢所在。 ## 怎么用協程 ~~~kotlin launch(Dispatchers.IO) { val image = getImage(imageId) } ~~~ 這個launch函數,具體的含義就是我要創建一個新的協程,并在指定線程上運行它。這個被創建被運行的所謂協程是誰,就是你傳給launch函數的那些代碼,這一段連續代碼就叫做一個協程。 ### 什么時候用協程? 當于需要并發任務,切線程或者指定線程的時候。 協程中卻有一個很實用的函數:`withContext`。這個函數可以切換到指定的線程,并在閉包內的邏輯執行結束之后,自動把線程切回去繼續執行。 ~~~kotlin coroutineScope.launch(Dispatchers.Main) { // ?? 在 UI 線程開始 val image = withContext(Dispatchers.IO) { // ?? 切換到 IO 線程,并在執行完成后切回 UI 線程 getImage(imageId) // ?? 將會運行在 IO 線程 } avatarIv.setImageBitmap(image) // ?? 回到 UI 線程更新 UI } ~~~ 這種寫法看上去好像和剛才那種區別不大,但如果你需要頻繁地進行線程切換,這種寫法的優勢就會體現出來。可以參考下面的對比: ~~~kotlin // 第一種寫法 coroutineScope.launch(Dispatchers.IO) { ... launch(Dispatchers.Main){ ... launch(Dispatchers.IO) { ... launch(Dispatchers.Main) { ... } } } } // 通過第二種寫法來實現相同的邏輯 coroutineScope.launch(Dispatchers.Main) { ... withContext(Dispatchers.IO) { ... } ... withContext(Dispatchers.IO) { ... } ... } ~~~ 由于可以"自動切回來",消除了并發代碼在協作時的嵌套。由于消除了嵌套關系,我們甚至可以把`withContext`放進一個單獨的函數里面: ~~~kotlin launch(Dispatchers.Main) { // ?? 在 UI 線程開始 val image = getImage(imageId) avatarIv.setImageBitmap(image) // ?? 執行結束后,自動切換回 UI 線程 } // ?? fun getImage(imageId: Int) = withContext(Dispatchers.IO) { ... } ~~~ 這就是之前說的「用同步的方式寫異步的代碼」了。 不過如果只是這樣寫,編譯器是會報錯的: ~~~kotlin fun getImage(imageId: Int) = withContext(Dispatchers.IO) { // IDE 報錯 Suspend function'withContext' should be called only from a coroutine or another suspend funcion } ~~~ 意思是說,`withContext`是一個`suspend`函數,它需要在協程或者是另一個`suspend`函數中調用。 `suspend`是 Kotlin 協程最核心的關鍵字,它的中文意思是「暫停」或者「可掛起」。如果你去看一些技術博客或官方文檔的時候,大概可以了解到:「代碼執行到`suspend`函數的時候會『掛起』,并且這個『掛起』是非阻塞式的,它不會阻塞你當前的線程。」 上面報錯的代碼,其實只需要在前面加一個`suspend`就能夠編譯通過: ~~~kotlin //?? suspend fun getImage(imageId: Int) = withContext(Dispatchers.IO) { ... } ~~~ ## 總結 協程到底是什么?其實**它就是一個比較方便的線程框架**,網絡上的什么像是線程,但又不是線程,它是用戶態的,它是協作式的,這些云里霧里,晦澀難懂的標題式答案都不正確。 好處:方便 最大的好處:在它能夠在同一個代碼塊里進行多次的線程切換 # Kotlin 協程的掛起
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看