Kotlin Coroutines鍦ˋndroid涓殑瀹炶返

Coroutines鍦ˋndroid涓殑瀹炶返

鍓嶉潰涓ょ瘒鏂囩珷璁蹭簡鍗忕▼鐨勫熀纭�鐭ヨ瘑鍜屽崗绋嬬殑閫氫俊.
瑙�:

  • Kotlin Coroutines涓嶅鏉�, 鎴戞潵甯綘鐞嗕竴鐞�
  • Kotlin鍗忕▼閫氫俊鏈哄埗: Channel
    涓剧殑渚嬪瓙鍙兘绂诲疄闄呯殑搴旂敤浠g爜姣旇緝閬ヨ繙.

杩欑瘒鎴戜滑灏变粠Android搴旂敤鐨勮搴�, 鐪嬬湅瀹炶返涓兘鏈夊摢浜涘湴鏂瑰彲浠ョ敤鍒板崗绋�.

Coroutines鐨勭敤閫�

Coroutines鍦ˋndroid涓彲浠ュ府鎴戜滑鍋氫粈涔�:

  • 鍙栦唬callbacks, 绠�鍖栦唬鐮�, 鏀瑰杽鍙鎬�.
  • 淇濊瘉Main safety.
  • 缁撴瀯鍖栫鐞嗗拰鍙栨秷浠诲姟, 閬垮厤娉勬紡.

杩欐湁涓�涓緥瀛�:

suspend fun fetchDocs() {                      // Dispatchers.Main
    val result = get("developer.android.com")  // Dispatchers.Main
    show(result)                               // Dispatchers.Main
}

suspend fun get(url: String) =                 // Dispatchers.Main
    withContext(Dispatchers.IO) {              // Dispatchers.IO (main-safety block)
        /* perform network IO here */          // Dispatchers.IO (main-safety block)
    }                                          // Dispatchers.Main
}

杩欓噷get鏄竴涓�suspend鏂规硶, 鍙兘鍦ㄥ彟涓�涓�suspend鏂规硶鎴栬�呭湪涓�涓崗绋嬩腑璋冪敤.

get鏂规硶鍦ㄤ富绾跨▼琚皟鐢�, 瀹冨湪寮�濮嬭姹備箣鍓峴uspend浜嗗崗绋�, 褰撹姹傝繑鍥�, 杩欎釜鏂规硶浼歳esume鍗忕▼, 鍥炲埌涓荤嚎绋�. 缃戠粶璇锋眰涓嶄細block涓荤嚎绋�.

main-safety鏄浣曚繚璇佺殑鍛�?

dispatcher鍐冲畾浜嗗崗绋嬪湪浠�涔堢嚎绋嬩笂鎵ц. 姣忎釜鍗忕▼閮芥湁dispatcher. 鍗忕▼suspend鑷繁, dispatcher璐熻矗resume瀹冧滑.

  • Dispatchers.Main: 涓荤嚎绋�: UI浜や簰, 鏇存柊LiveData, 璋冪敤suspend鏂规硶绛�.
  • Dispatchers.IO: IO鎿嶄綔, 鏁版嵁搴撴搷浣�, 璇诲啓鏂囦欢, 缃戣矾璇锋眰.
  • Dispatchers.Default: 涓荤嚎绋嬩箣澶栫殑璁$畻浠诲姟(CPU-intensive work), 鎺掑簭, 瑙f瀽JSON绛�.

涓�涓ソ鐨勫疄璺垫槸浣跨敤withContext()鏉ョ‘淇濇瘡涓柟娉曢兘鏄痬ain-safe鐨�, 璋冪敤鑰呭彲浠ュ湪涓荤嚎绋嬮殢鎰忚皟鐢�, 涓嶇敤鍏冲績閲岄潰鐨勪唬鐮佸埌搴曟槸鍝釜绾跨▼鐨�.

绠$悊鍗忕▼

涔嬪墠璁睸cope鍜孲tructured Concurrency鐨勬椂鍊欐彁杩�, scope鏈�鍏稿瀷鐨勫簲鐢ㄥ氨鏄寜鐓у璞$殑鐢熷懡鍛ㄦ湡, 鑷姩绠$悊鍏朵腑鐨勫崗绋�, 鍙婃椂鍙栨秷, 閬垮厤娉勬紡鍜屽啑浣欐搷浣�.

鍦ㄥ崗绋嬩箣涓啀鍚姩鏂扮殑鍗忕▼, 鐖跺瓙鍗忕▼鏄叡浜玸cope鐨�, 涔熷嵆scope浼歵rack鍏朵腑鎵�鏈夌殑鍗忕▼.

鍗忕▼琚彇娑堜細鎶涘嚭CancellationException.

coroutineScope鍜�supervisorScope鍙互鐢ㄦ潵鍦╯uspend鏂规硶涓惎鍔ㄥ崗绋�. Structured concurrency淇濊瘉: 褰撲竴涓猻uspend鍑芥暟杩斿洖鏃�, 瀹冪殑鎵�鏈夊伐浣滈兘鎵ц瀹屾瘯.

瀹冧滑涓よ�呯殑鍖哄埆鏄�: 褰撳瓙鍗忕▼鍙戠敓閿欒鐨勬椂鍊�, coroutineScope浼氬彇娑坰cope涓殑鎵�鏈夌殑瀛愬崗绋�, 鑰�supervisorScope涓嶄細鍙栨秷娌℃湁鍙戠敓閿欒鐨勫叾浠栧瓙鍗忕▼.

Activity/Fragment & Coroutines

鍦ˋndroid涓�, 鍙互鎶婁竴涓睆骞�(Activity/Fragment)鍜屼竴涓�CoroutineScope鍏宠仈, 杩欐牱鍦ˋctivity鎴朏ragment鐢熷懡鍛ㄦ湡缁撴潫鐨勬椂鍊�, 鍙互鍙栨秷杩欎釜scope涓嬬殑鎵�鏈夊崗绋�, 濂介伩鍏嶅崗绋嬫硠婕�.

鍒╃敤CoroutineScope鏉ュ仛杩欎欢浜嬫湁涓ょ鏂规硶: 鍒涘缓涓�涓�CoroutineScope瀵硅薄鍜宎ctivity鐨勭敓鍛藉懆鏈熺粦瀹�, 鎴栬�呰activity瀹炵幇CoroutineScope鎺ュ彛.

鏂规硶1: 鎸佹湁scope寮曠敤:

class Activity {
    private val mainScope = MainScope()
    
    fun destroy() {
        mainScope.cancel()
    }
}    

鏂规硶2: 瀹炵幇鎺ュ彛:

class Activity : CoroutineScope by CoroutineScope(Dispatchers.Default) {
    fun destroy() {
        cancel() // Extension on CoroutineScope
    }
}

榛樿绾跨▼鍙互鏍规嵁瀹為檯鐨勯渶瑕佹寚瀹�.
Fragment鐨勫疄鐜扮被浼�, 杩欓噷涓嶅啀涓句緥.

ViewModel & Coroutines

Google鐩墠鎺ㄥ箍鐨凪VVM妯″紡, 鐢盫iewModel鏉ュ鐞嗛�昏緫, 鍦╒iewModel涓娇鐢ㄥ崗绋�, 鍚屾牱涔熸槸鍒╃敤scope鏉ュ仛绠$悊.

ViewModel鍦ㄥ睆骞曟棆杞殑鏃跺�欏苟涓嶄細閲嶅缓, 鎵�浠ヤ笉鐢ㄦ媴蹇冨崗绋嬪湪杩欎釜杩囩▼涓鍙栨秷鍜岄噸鏂板紑濮�.

鏂规硶1: 鑷繁鍒涘缓scope

private val viewModelJob = Job()

private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

榛樿鏄湪UI绾跨▼.
CoroutineScope鐨勫弬鏁版槸CoroutineContext, 鏄竴涓厤缃睘鎬х殑闆嗗悎. 杩欓噷鎸囧畾浜哾ispatcher鍜宩ob.

鍦╒iewModel琚攢姣佺殑鏃跺��:

override fun onCleared() {
    super.onCleared()
    viewModelJob.cancel()
}

杩欓噷viewModelJob鏄痷iScope鐨刯ob, 鍙栨秷浜唙iewModelJob, 鎵�鏈夎繖涓猻cope涓嬬殑鍗忕▼閮戒細琚彇娑�.

涓�鑸�CoroutineScope鍒涘缓鐨勬椂鍊欎細鏈変竴涓粯璁ょ殑job, 鍙互杩欐牱鍙栨秷:

uiScope.coroutineContext.cancel()

鏂规硶2: 鍒╃敤viewModelScope

濡傛灉鎴戜滑鐢ㄤ笂闈㈢殑鏂规硶, 鎴戜滑闇�瑕佺粰姣忎釜ViewModel閮借繖鏍峰啓. 涓轰簡閬垮厤杩欎簺boilerplate code, 鎴戜滑鍙互鐢�viewModelScope.

娉�: 瑕佷娇鐢╲iewModelScope闇�瑕佹坊鍔犵浉搴旂殑KTX渚濊禆.

  • For ViewModelScope, use androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-beta01 or higher.

viewModelScope缁戝畾鐨勬槸Dispatchers.Main, 浼氳嚜鍔ㄥ湪ViewModel clear鐨勬椂鍊欒嚜鍔ㄥ彇娑�.

鐢ㄧ殑鏃跺�欑洿鎺ョ敤灏卞彲浠ヤ簡:

class MainViewModel : ViewModel() {
    // Make a network request without blocking the UI thread
    private fun makeNetworkRequest() {
       // launch a coroutine in viewModelScope 
        viewModelScope.launch(Dispatchers.IO) {
            // slowFetch()
        }
    }

    // No need to override onCleared()
}

鎵�鏈夌殑setting up鍜宑learing宸ヤ綔閮芥槸搴撳畬鎴愮殑.

LifecycleScope & Coroutines

姣忎竴涓�Lifecycle瀵硅薄閮芥湁涓�涓�LifecycleScope.

鍚屾牱涔熼渶瑕佹坊鍔犱緷璧�:

  • For LifecycleScope, use androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01 or higher.

瑕佽闂�CoroutineScope鍙互鐢�lifecycle.coroutineScope鎴栬��lifecycleOwner.lifecycleScope灞炴��.

姣斿:

activity.lifecycleScope.launch {}
fragment.lifecycleScope.launch {}
fragment.viewLifecycleOwner.launch {}

lifecycleScope鍙互鍚姩鍗忕▼, 褰揕ifecycle缁撴潫鐨勬椂鍊�, 浠讳綍杩欎釜scope涓惎鍔ㄧ殑鍗忕▼閮戒細琚彇娑�.

杩欐瘮杈冮�傚悎浜庡鐞嗕竴浜涘甫delay鐨刄I鎿嶄綔, 姣斿闇�瑕佺敤handler.postDelayed鐨勬洿鏂癠I鐨勬搷浣�, 鏈夊涓搷浣滅殑鏃跺�欏祵濂楅毦鐪�, 杩樺鏄撴湁娉勬紡闂.

鐢ㄤ簡lifecycleScope涔嬪悗, 鏃㈤伩鍏嶄簡宓屽浠g爜, 鍙堣嚜鍔ㄥ鐞嗕簡鍙栨秷.

lifecycleScope.launch {
    delay(DELAY)
    showFullHint()
    delay(DELAY)
    showSmallHint()
}

LifecycleScope鍜孷iewModelScope

浣嗘槸LifecycleScope鍚姩鐨勫崗绋嬪嵈涓嶉�傚悎璋冪敤repository鐨勬柟娉�. 鍥犱负瀹冪殑鐢熷懡鍛ㄦ湡鍜孉ctivity/Fragment鏄竴鑷寸殑, 澶鐗囧寲浜�, 瀹规槗琚彇娑�, 閫犳垚娴垂.

璁惧鏃嬭浆鏃�, Activity浼氳閲嶅缓, 濡傛灉鍙栨秷璇锋眰鍐嶉噸鏂板紑濮�, 浼氶�犳垚涓�绉嶆氮璐�.

鍙互鎶婅姹傛斁鍦╒iewModel涓�, UI灞傞噸鏂版敞鍐岃幏鍙栫粨鏋�. viewModelScope鍜�lifecycleScope鍙互缁撳悎璧锋潵浣跨敤.

涓句緥: ViewModel杩欐牱鍐�:

class NoteViewModel: ViewModel {
    val noteDeferred = CompletableDeferred()
    
    viewModelScope.launch {
        val note = repository.loadNote()
        noteDeferred.complete(note)
    }
    
    suspend fun loadNote(): Note = noteDeferred.await()
}

鑰屾垜浠殑UI涓�:

fun onCreate() {
    lifecycleScope.launch {
        val note = userViewModel.loadNote()
        updateUI(note)
    }
}

杩欐牱鍋氫箣鍚庣殑濂藉:

  • ViewModel淇濊瘉浜嗘暟鎹姹傛病鏈夋氮璐�, 灞忓箷鏃嬭浆涓嶄細閲嶆柊鍙戣捣璇锋眰.
  • lifecycleScope淇濊瘉浜唙iew娌℃湁leak.

鐗瑰畾鐢熷懡鍛ㄦ湡闃舵

灏界scope鎻愪緵浜嗚嚜鍔ㄥ彇娑堢殑鏂瑰紡, 浣犲彲鑳借繕鏈変竴浜涢渶姹傞渶瑕侀檺鍒跺湪鏇村姞鍏蜂綋鐨勭敓鍛藉懆鏈熷唴.

姣斿, 涓轰簡鍋�FragmentTransaction, 浣犲繀椤荤瓑鍒�Lifecycle鑷冲皯鏄�STARTED.

涓婇潰鐨勪緥瀛愪腑, 濡傛灉闇�瑕佹墦寮�涓�涓柊鐨刦ragment:

fun onCreate() {
    lifecycleScope.launch {
        val note = userViewModel.loadNote()
        fragmentManager.beginTransaction()....commit() //IllegalStateException
    }
}

寰堝鏄撳彂鐢�IllegalStateException.

Lifecycle鎻愪緵浜�:
lifecycle.whenCreated, lifecycle.whenStarted, lifecycle.whenResumed.

濡傛灉娌℃湁鑷冲皯杈惧埌鎵�瑕佹眰鐨勬渶灏忕敓鍛藉懆鏈�, 鍦ㄨ繖浜涘潡涓惎鍔ㄧ殑鍗忕▼浠诲姟, 灏嗕細suspend.

鎵�浠ヤ笂闈㈢殑渚嬪瓙鏀规垚杩欐牱:

fun onCreate() {
    lifecycleScope.launchWhenStarted {
        val note = userViewModel.loadNote()
        fragmentManager.beginTransaction()....commit()
    }
}

濡傛灉Lifecycle瀵硅薄琚攢姣�(state==DESTROYED), 杩欎簺when鏂规硶涓殑鍗忕▼涔熶細琚嚜鍔ㄥ彇娑�.

LiveData & Coroutines

LiveData鏄竴涓緵UI瑙傚療鐨剉alue holder.

LiveData鐨勬暟鎹彲鑳芥槸寮傛鑾峰緱鐨�, 鍜屽崗绋嬬粨鍚�:

val user: LiveData = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

杩欎釜渚嬪瓙涓殑liveData鏄竴涓猙uilder function, 瀹冭皟鐢ㄤ簡璇诲彇鏁版嵁鐨勬柟娉�(涓�涓�suspend鏂规硶), 鐒跺悗鐢�emit()鏉ュ彂灏勭粨鏋�.

鍚屾牱涔熸槸闇�瑕佹坊鍔犱緷璧栫殑:

  • For liveData, use androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01 or higher.

瀹為檯涓婁娇鐢ㄦ椂, 鍙互emit()澶氭:

val user: LiveData = liveData {
    emit(Result.loading())
    try {
        emit(Result.success(fetchUser()))
    } catch(ioException: Exception) {
        emit(Result.error(ioException))
    }
}

姣忔emit()璋冪敤閮戒細suspend杩欎釜鍧�, 鐩村埌LiveData鐨勫�煎湪涓荤嚎绋嬭璁剧疆.

LiveData杩樺彲浠ュ仛鍙樻崲:

class MyViewModel: ViewModel() {
    private val userId: LiveData = MutableLiveData()
    val user = userId.switchMap { id ->
        liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
            emit(database.loadUserById(id))
        }
    }
}

濡傛灉鏁版嵁搴撶殑鏂规硶杩斿洖鐨勭被鍨嬫槸LiveData绫诲瀷, emit()鏂规硶鍙互鏀规垚emitSource(). 渚嬪瓙瑙�: Use coroutines with LiveData.

缃戠粶/鏁版嵁搴� & Coroutines

鏍规嵁Architecture Components鐨勬瀯寤烘ā寮�:

  • ViewModel璐熻矗鍦ㄤ富绾跨▼鍚姩鍗忕▼, 娓呯悊鏃跺彇娑堝崗绋�, 鏀跺埌鏁版嵁鏃剁敤LiveData浼犵粰UI.
  • Repository鏆撮湶suspend鏂规硶, 纭繚鏂规硶main-safe.
  • 鏁版嵁搴撳拰缃戠粶鏆撮湶suspend鏂规硶, 纭繚鏂规硶main-safe. Room鍜孯etrofit閮芥槸绗﹀悎杩欎釜pattern鐨�.

Repository鏆撮湶suspend鏂规硶, 鏄富绾跨▼safe鐨�, 濡傛灉瑕佸缁撴灉鍋氫竴浜沨eavy鐨勫鐞�, 姣斿杞崲璁$畻, 闇�瑕佺敤withContext鑷纭畾涓荤嚎绋嬩笉琚樆濉�.

Retrofit & Coroutines

Retrofit浠�2.6.0寮�濮嬫彁渚涗簡瀵瑰崗绋嬬殑鏀寔.

瀹氫箟鏂规硶鐨勬椂鍊欏姞涓�suspend鍏抽敭瀛�:

interface GitHubService {
    @GET("orgs/{org}/repos?per_page=100")
    suspend fun getOrgRepos(
        @Path("org") org: String
    ): List
}

suspend鏂规硶杩涜璇锋眰鐨勬椂鍊�, 涓嶄細闃诲绾跨▼.
杩斿洖鍊煎彲浠ョ洿鎺ユ槸缁撴灉绫诲瀷, 鎴栬�呭寘涓�灞�Response:

@GET("orgs/{org}/repos?per_page=100")
suspend fun getOrgRepos(
    @Path("org") org: String
): Response>

Room & Coroutines

Room浠�2.1.0鐗堟湰寮�濮嬫彁渚涘鍗忕▼鐨勬敮鎸�. 鍏蜂綋灏辨槸DAO鏂规硶鍙互鏄�suspend鐨�.

@Dao
interface UsersDao {
    @Query("SELECT * FROM users")
    suspend fun getUsers(): List

    @Insert
    suspend fun insertUser(user: User)

    @Update
    suspend fun updateUser(user: User)

    @Delete
    suspend fun deleteUser(user: User)
}

Room浣跨敤鑷繁鐨刣ispatcher鏉ョ‘瀹氭煡璇㈣繍琛屽湪鍚庡彴绾跨▼.
鎵�浠ヤ綘鐨勪唬鐮佷笉搴旇浣跨敤withContext(Dispatchers.IO), 浼氳浠g爜鍙樺緱澶嶆潅骞朵笖鏌ヨ鍙樻參.

鏇村鍐呭鍙: Room 馃敆 Coroutines.

WorkManager & Coroutines

WorkManager涔熸湁鍗忕▼鐗堟湰, 娣诲姞work-runtime-ktx渚濊禆, 鐒跺悗鏀瑰彉鍩虹被, 浠ュ墠缁ф壙Worker, 鐜板湪缁ф壙CoroutineWorker.
姣斿:

class UploadNotesWorker(...) : CoroutineWorker(...) {
    suspend fun doWork(): Result {
        val newNotes = db.queryNewNotes()
        noteService.uploadNotes(newNotes)
        db.markAsSynced(newNotes)
        return Result.success()
    }
}

杩欐浠g爜鍏朵腑鏁版嵁搴撶敤Room, 缃戠粶鐢�Retrofit, 杩欐牱3涓柟娉曢兘鏄�suspend鐨�.

鐢ㄤ簡鍗忕▼鐨勭増鏈箣鍚�, 鍙栨秷鎿嶄綔鏇村鏄�.

鏇磋缁嗙殑璇风湅: Threading in CoroutineWorker

寮傚父澶勭悊

suspend鏂规硶涓殑寮傚父灏嗕細resume鍒拌皟鐢ㄨ��.
鏇翠竴鑸殑, 鍗忕▼涓殑閿欒浼氶�氱煡鍒板畠鐨勮皟鐢ㄨ�呮垨鑰卻cope.

launch鍜�async鐨勫紓甯稿鐞嗕笉鍚�.
杩欐槸鍥犱负async杩斿洖鍊�, 鏄湡寰�await璋冪敤鐨�, 鎵�浠ヤ細鎸佹湁寮傚父, 鍦ㄨ皟鐢�await()鐨勬椂鍊欐墠杩斿洖(缁撴灉鎴栧紓甯�).
鎵�浠ュ鏋�await()娌℃湁琚皟鐢ㄧ殑璇�, 寮傚父灏变細琚悆浜�.

娴嬭瘯

鎺ㄨ崘浣跨敤runBlockingTest鏉ユ浛鎹�runBlocking, 灏嗕細鍒╃敤virtual time, 鑺傜渷娴嬭瘯鏃堕棿.

鏇村鍏充簬娴嬭瘯鐨勮缁嗗唴瀹硅: kotlinx-coroutines-test

鍙傝��

  • Codelab: Using Kotlin Coroutines in your Android App
  • Improve app performance with Kotlin coroutines
  • Use Kotlin coroutines with Architecture components
  • Coroutine Context and Dispatchers
  • Threading in CoroutineWorker

鍗氬:

  • Kotlin Coroutines patterns & anti-patterns
  • Coroutines on Android (part II): Getting started
  • Coroutines On Android (part III): Real work
  • Part 2 鈥� Coroutine Cancellation and Structured Concurrency
  • Room 馃敆 Coroutines

Google鐨勮棰�:

  • LiveData with Coroutines and Flow (Android Dev Summit '19)
  • Understand Kotlin Coroutines on Android (Google I/O'19)

娆㈣繋鍏虫敞寰俊鍏紬鍙�: 鍦i獞澹玏ind
Kotlin Coroutines鍦ˋndroid涓殑瀹炶返_第1张图片

你可能感兴趣的:(Kotlin Coroutines鍦ˋndroid涓殑瀹炶返)