最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Kotlin Suspend掛起函數(shù)的使用詳解

 更新時間:2023年02月17日 14:16:58   作者:破浪會有時  
這里介紹 Kotlin Suspend 掛起函數(shù)的使用。掛起(suspend)函數(shù)是所有協(xié)程的核心。 掛起函數(shù)可以執(zhí)行長時間運行的操作并等待它完成而不會阻塞主線程。Kotlin 的 suspend 關(guān)鍵字可以幫助我們消除回調(diào),用同步的寫法寫異步

總結(jié)

掛起(suspend)函數(shù)是所有協(xié)程的核心。 掛起函數(shù)可以執(zhí)行長時間運行的操作并等待它完成而不會阻塞主線程。

掛起函數(shù)的語法與常規(guī)函數(shù)的語法類似,不同之處在于添加了suspend關(guān)鍵字。 它可以接受一個參數(shù)并有一個返回類型。 但是,掛起函數(shù)只能由另一個掛起函數(shù)或在協(xié)程內(nèi)調(diào)用。

suspend fun backgroundTask(param: Int): Int {
     // long running operation
}

在背后,編譯器將掛起函數(shù)轉(zhuǎn)換為另一個沒有掛起關(guān)鍵字的函數(shù),該函數(shù)接受一個類型為 Continuation<T> 的附加參數(shù)。 例如,上面的函數(shù)將由編譯器轉(zhuǎn)換為:

fun backgroundTask(param: Int, callback: Continuation<Int>): Int {
   // long running operation
}

本質(zhì)

  • 掛起函數(shù)只能在協(xié)程或者其他掛起函數(shù)中調(diào)用。
  • 掛起的對象是協(xié)程:launch ,async 或者其他函數(shù)創(chuàng)建的協(xié)程,在執(zhí)行到某一個 suspend 函數(shù)的時候,這個協(xié)程會被掛起,即,從正在執(zhí)行它的線程上脫離。就是說,當前線程跳過這個掛起函數(shù),繼續(xù)往下運行,但另一方面,線程的代碼在到達 suspend 函數(shù)的時候被掐斷,接下來協(xié)程會從這個 suspend 函數(shù)開始繼續(xù)往下執(zhí)行,不過是在指定的線程,執(zhí)行完后,返回到之前掛起它的線程;
  • 簡單來講,在 Kotlin 中所謂的掛起,就是一個稍后會被自動切回來的線程調(diào)度操作;
  • 掛起函數(shù)的特點是使用同步的方式完成異步任務(wù)。
  • withContext 的作用就是指定切換的線程,比如:suspend fun suspendingGetImage(id: String) = withContext(Dispatchers.IO)。

何時使用

如果你的某個函數(shù)比較耗時,也就是要等的操作,那就把它寫成 suspend 函數(shù)。這就是原則。

耗時操作一般分為兩類:I/O 操作和 CPU 計算工作。比如文件的讀寫、網(wǎng)絡(luò)交互、圖片的模糊處理,都是耗時的,通通可以把它們寫進 suspend 函數(shù)里。

另外這個「耗時」還有一種特殊情況,就是這件事本身做起來并不慢,但它需要等待,比如 5 秒鐘之后再做這個操作。這種也是 suspend 函數(shù)的應(yīng)用場景。

消除回調(diào)

假設(shè) postItem 由三個有依賴關(guān)系的異步子任務(wù)組成: requestToken,createPostprocessPost,這三個函數(shù)都是基于回調(diào)的 API:

// 三個基于回調(diào)的 API
fun requestToken(block: (String) -> Unit)
fun createPost(
  token: String,
  item: Item,
  block: (Post) -> Unit)
)
fun processPost(post: Post)
fun postItem(item: Item) {
  requestToken { token ->
    createPost(token, item) { post ->
      processPost(post)
    }
  }
}

可以看到基于回調(diào)的 API 很容易造成大量縮進。如果代碼中再加上一些條件、循環(huán)的邏輯,那么代碼可讀性會大大降低。Kotlin 的 suspend 關(guān)鍵字可以幫助我們消除回調(diào),用同步的寫法寫異步:

suspend fun requestToken(): String
suspend fun createPost(token: String, item: Item): Post
suspend fun processPost(post)
suspend fun postItem(item: Item) {
  val token = ?? requestToken()
  val post = ?? createPost(token, item)
  ?? processPost(post)
}

由于 createPost 這些方法實際上是耗時的 IO 異步操作,需要等到拿到返回值才能執(zhí)行后面的邏輯,但我們又不希望阻塞當前線程(通常是主線程),因此最終必須實現(xiàn)某種消息傳遞的機制,讓后臺線程做完耗時操作以后把結(jié)果傳給主線程。

一些例子

一個基本的使用方式:

suspend fun getUserInfo(): String {
    withContext(Dispatchers.IO) {
        delay(1000L)
    }
    return "BoyCoder"
}

在 Room 里面會經(jīng)常用到:

@Dao
interface RegisterDatabaseDao {
    @Insert
    suspend fun insert(register: RegisterEntity)
    //@Delete
    //suspend  fun deleteSubscriber(register: RegisterEntity):Int
    @Query("SELECT * FROM Register_users_table ORDER BY userId DESC")
    fun getAllUsers(): LiveData<List<RegisterEntity>>
    @Query("DELETE FROM Register_users_table")
    suspend fun deleteAll(): Int
    @Query("SELECT * FROM Register_users_table WHERE user_name LIKE :userName")
    suspend fun getUsername(userName: String): RegisterEntity?
}

最后這個例子可以直接在 Kotlin Playground 上跑。

import kotlinx.coroutines.*
import java.util.*
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.Period
import java.text.SimpleDateFormat
import java.lang.Thread
var dateTimeNow = ""
@OptIn(DelicateCoroutinesApi::class)
fun main() = runBlocking{
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("code start: ${dateTimeNow}")
    launch { 
        dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    	println("1 code start: ${dateTimeNow}")
        delay(2000L)
        dateTimeNow = dateAsString(Calendar.getInstance().time.time)
        println("2 Task from runBlocking: ${dateTimeNow}")
    }
    coroutineScope { // Creates a new coroutine scope
        dateTimeNow = dateAsString(Calendar.getInstance().time.time)
        println("3 coroutineScope created: ${dateTimeNow}")
        val job = launch {
            dateTimeNow = dateAsString(Calendar.getInstance().time.time)
            println("4 coroutineScope job starts: ${dateTimeNow}")
            val one = doSomethingUsefulOne()
        	  val two = doSomethingUsefulTwo()
            dateTimeNow = dateAsString(Calendar.getInstance().time.time)
            println("5 coroutineScope job ends: ${dateTimeNow}")
        }
        val job2 = launch {
            dateTimeNow = dateAsString(Calendar.getInstance().time.time)
            println("11 coroutineScope job2 starts: ${dateTimeNow}")
        }
        delay(1000L)
        dateTimeNow = dateAsString(Calendar.getInstance().time.time)
        println("6 Task from first coroutine scope: ${dateTimeNow}") // Printed before initial launch
        //job.cancel() // This cancels nested launch's execution
    }
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("code end: ${dateTimeNow}")
}
fun dateAsString(
    dateInMillis: Long,
    format: String = "yyyyMMdd HH:mm:ss",
    locale: Locale = Locale.getDefault()
): String {
    val date = Date(dateInMillis)
    val formatter = SimpleDateFormat(format, locale)
    return formatter.format(date)
}
suspend fun doSomethingUsefulOne(): Int {
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("7 第一個掛起函數(shù)開始: ${dateTimeNow}")
    delay(1000L) // 假設(shè)我們在這里做了某些有用的工作
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("8 第一個掛起函數(shù)結(jié)束: ${dateTimeNow}")
    return 1
}
suspend fun doSomethingUsefulTwo(): Int {
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("9 第二個掛起函數(shù)開始: ${dateTimeNow}")
    delay(2000L) // 假設(shè)我們在這里也做了某些有用的工作
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("10 第二個掛起函數(shù)結(jié)束: ${dateTimeNow}")
    coroutineScope {
        val job = launch {
            doSomethingUsefulThree()
            doSomethingUsefulFour()
        }
    }
    return 2
}
suspend fun doSomethingUsefulThree(): Int {
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("9 第三個掛起函數(shù)開始: ${dateTimeNow}")
    delay(3000L) // 假設(shè)我們在這里也做了某些有用的工作
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("10 第三個掛起函數(shù)結(jié)束: ${dateTimeNow}")
    return 3
}
suspend fun doSomethingUsefulFour(): Int {
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("9 第四個掛起函數(shù)開始: ${dateTimeNow}")
    delay(3000L) // 假設(shè)我們在這里也做了某些有用的工作
    dateTimeNow = dateAsString(Calendar.getInstance().time.time)
    println("10 第四個掛起函數(shù)結(jié)束: ${dateTimeNow}")
    return 4
}

打印的結(jié)果如下:

code start: 20221009 03:15:55
3 coroutineScope created: 20221009 03:15:55
1 code start: 20221009 03:15:55
4 coroutineScope job starts: 20221009 03:15:55
11 coroutineScope job2 starts: 20221009 03:15:55
7 第一個掛起函數(shù)開始: 20221009 03:15:55
6 Task from first coroutine scope: 20221009 03:15:56
8 第一個掛起函數(shù)結(jié)束: 20221009 03:15:56
9 第二個掛起函數(shù)開始: 20221009 03:15:56
2 Task from runBlocking: 20221009 03:15:57
10 第二個掛起函數(shù)結(jié)束: 20221009 03:15:58
9 第三個掛起函數(shù)開始: 20221009 03:15:58
10 第三個掛起函數(shù)結(jié)束: 20221009 03:16:01
9 第四個掛起函數(shù)開始: 20221009 03:16:01
10 第四個掛起函數(shù)結(jié)束: 20221009 03:16:04
5 coroutineScope job ends: 20221009 03:16:04
code end: 20221009 03:16:04

有幾點需要說明:

  • launch 是 CoroutineScope 的一個擴展函數(shù),該方法在不阻塞當前線程的情況下啟動新的協(xié)程,launch 里面的代碼雖然有掛起函數(shù),但還是會按順序運行(注意,這里的掛起函數(shù)并沒有用withContext選擇去指定切換的線程);
  • coroutineScope 本身就是一個掛起函數(shù),會掛起當前的協(xié)程。coroutineScope 里面的代碼除了 launch,其他按照順序運行,而 coroutineScope 里面可以 launch 多個 job,這多個 job 是并行的;
  • suspend 掛起函數(shù)里面的掛起函數(shù)是(默認)串行的(即,用同步的方式實現(xiàn)異步)。

到此這篇關(guān)于Kotlin Suspend掛起函數(shù)的使用詳解的文章就介紹到這了,更多相關(guān)Kotlin Suspend掛起函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

仙桃市| 洪江市| 南岸区| 柳州市| 敖汉旗| 平泉县| 新巴尔虎左旗| 衡南县| 阜平县| 遂平县| 永年县| 扶余县| 连城县| 云南省| 八宿县| 内江市| 文昌市| 铅山县| 恭城| 德保县| 东乡县| 石柱| 富川| 河间市| 连平县| 湘潭市| 龙门县| 兴仁县| 南宁市| 洛南县| 涟水县| 韩城市| 香港| 靖安县| 冀州市| 廉江市| 舒城县| 阿克陶县| 玛纳斯县| 临江市| 衡水市|