Android

Kotlin Coroutines Temelleri – Basit Android Uygulaması Demosu

Bu basit Android uygulamasını, Kotlin eşyordamlarının temel kullanımlarını anlamama yardımcı olması için oluşturdum. Uygulama, eşyordam işlerinin nasıl oluşturulacağını ve bunların eşzamanlı olarak nasıl çalıştırılacağını gösterir. Muhtemelen kullanım durumlarının %100’ünü, belki de en az %90’ını kapsamayacaktır?

Uygulama ayrıca basit kullanır MVVM mimarisi (olmadan Model tam olarak).

Uygulamaya Genel Bakış

Bu uygulamada 3 düğme ve 2 ekran metni (sol ve sağ) kullanıcı arayüzü vardır.

  • Başlatmak ve zaman uyumsuz düğmeler her ikisini de günceller sol metin ve doğru metin kullanıcı arayüzü aynı anda
  • sol metin ve doğru metin başlatıldı -1 geçersiz değer olarak
  • Ne zaman Başlatmak veya zaman uyumsuz butonuna tıklanır, güncellemek için eşyordamlar oluşturulur sol metin kullanıcı arayüzü 09 ve doğru metin kullanıcı arayüzü 1019
  • Eğer İptal butonuna tıklandığında, her iki metnin de güncellenmesi durdurulur ve değer olarak ayarlanır. -1.
  • Eğer hayırsa İptal butonuna tıklanır, her iki metin de son değere kadar güncellenmeye devam eder. 9 ve 19

Eşyordamlar oluşturmanın 2 yolu vardır:

  • CoroutineScope.launch
  • CoroutineScope.async

CoroutineScope.launch

Bir eşyordam oluşturmak için, CoroutineScope ilk. İçinde ViewModel, CorotineScope zaten oluşturuldu (yani viewModelScope). Bu nedenle, kendiniz oluşturmak yerine kullanmanız şiddetle tavsiye edilir. Bir fayda, tüm CoroutineScope çocuklar ne zaman otomatik olarak iptal edilecek ViewModel yok edildi.


currentJob = viewModelScope.launch {

    
    val job1 = launch {
        ...
    }

    
    val job2 = launch {
        ...
    }

    

    
    job1.join()
    job2.join()
    ...    
}

CoroutineScpoe.launch engellemeyen bir işlevdir ve geri döner Job hemen. Eşzamanlılık elde etmek için arayabiliriz CoroutineScpoe.launch aynı eşyordam kapsamında birden çok kez. job1 güncellemekten sorumludur. sol metin kullanıcı arayüzü ve job2 güncellemekten sorumludur. doğru metin kullanıcı arayüzü

İşin tamamlanmasını beklemek istiyorsanız, aramanız gerekir. Job.join() askıya alma işlevi. Bu, bir sonraki satıra geçmeden önce işin tamamlanmasını bekleyecektir.

CoroutineScope.async

Döndürülen değeri beklemek istediğimiz eşyordamı oluşturmak için kullanıyoruz CoroutineScope.async.

Benzer CoroutineScpoe.launch, CoroutineScope.async engellemeyen bir fonksiyondur. geri dönmek yerine Jobgeri döner Deferred<T>. içindeki son satır async blockdönüş türüdür T. Örneğin, getData() İadeler IntBöylece T dır-dir Int tip.


viewModelScope.launch {
    
    val deferred = async {  
        ...
        getData()  
    }  
    
    data.value = deferred.await()
    ...
}

Kullanmak yerine Job.join()sen ara Deferred<T>.awailt() için beklemek CoroutineScope.async bitirmek ve ayrıca değeri döndürmek için getData().

CoroutineScope.withContext()

Varsayılan olarak, eşyordamlar ana/UI iş parçacığında çalıştırılır. Ana/UI iş parçacığını engellememesi için uzun süren görevleri farklı iş parçacığına taşımalısınız.

Farklı bir konuya geçmek için şunları belirtirsiniz: CoroutineDispatcher. İşte ortak önceden tanımlanmış CoroutineDispatcher kullanabileceğimiz:

  • Dispatchers.Main – ana/UI iş parçacığı
  • Dispatchers.Default – CPU işlem dizisi
  • Dispatchers.IO – IO veya ağ işlemi iş parçacığı

Kendi konunuzu kullanmak için yeni bir konu/yeni konu oluşturabilirsiniz. CoroutineDispatcher kullanarak newSingleThreadContext("MyOwnThread"). Çoğu zaman önceden tanımlanmış CoroutineDispatcher yeterlidir.

ile bir eşyordam oluştururken launch veya asyncbelirtebilirsiniz CoroutineDispatcher.

viewModelScope.launch {
    
    launch(Dispatchers.Default) {
        loadData()
    }
    
    async(Dispatchers.Default) {
        loadData()
    }
}

Ancak, kullanmak daha iyi bir çözümdür. CoroutineScope.withContext() belirtmek yerine askıya alma işlevinde CoroutineDispatcher koroutin oluşturma sırasında. Bu, askıya alma işlevinin ana/UI iş parçacığından çağrılmasını güvenli hale getirdiği için önerilir.

private suspend fun loadData() {
    
    withContext(Dispatchers.Default) {
        ...
    }
}

lütfen aklınızda bulundurun CoroutineScope.withContext() yeni bir eşyordam oluşturmaz. Eşyordamları farklı bir iş parçacığına taşır.

Job.cancelAndJoin()

Bir eşyordam işini iptal etmek için Job.cancel() ve Job.join(). Çoğu zaman, sadece arayabilirsin Job.cancelAndJoin(). Lütfen bunu not al Job.cancelAndJoin() bir askıya alma işlevidir. Bu yüzden onu eşyordamın içinde aramanız gerekiyor.

fun onCancelButtonClick() {
    if (currentJob == null) return
    viewModelScope.launch() {
        currentJob!!.cancelAndJoin()
    }
}

currentJob daha önce oluşturulmuş mevcut bir eşyordam işidir.

kotlinx.coroutines.yield()

Dikkat edilmesi gereken önemli bir nokta eşyordam iptali işbirlikçidir. Bir eşyordam işbirlikçi olmayan iptal ise, onu iptal etmemizin hiçbir yolu yoktur. Eşyordam tamamlanıncaya kadar çalışmaya devam edecek, ancak Job.cancel() arandı.

Bir eşyordam iptali kooperatifi yapmak için şunları kullanabilirsiniz:

  • CoroutineScope.isActive
  • kotlinx.coroutines.yield()

CoroutineScope.isActive gereklidir CoroutineScope çağrılacak nesnedir ve eşyordamdan çıkmak için mantık eklemeniz gerekir, bu nedenle daha az esnektir. Dan beri yield() herhangi bir askıya alma işlevinde çağrılabilir, ben şahsen kullanmayı tercih ederim.

lütfen not edin kotlinx.coroutines.delay() ayrıca eşyordam iptalini kooperatif yapın.

Örneğin, aşağıdaki gibi uzun süredir devam eden bir göreviniz varsa, eşyordam hiçbir görevi yerine getirmeyecektir. Job.cancel() rica etmek.

private suspend fun simulateLongRunningTask() {  
    repeat(1_000_000) {  
        Thread.sleep(100)  
    }  
}

kabul etmesini sağlamak için Job.cancel() istek, sadece eklemeniz gerekir yield().

private suspend fun simulateLongRunningTask() {  
    repeat(1_000_000) {  
        Thread.sleep(100)  
        yield()
    }  
}

kotlinx.coroutines.JobCancellationException

Bir eşyordam iptali kabul edildiğinde, kotlinx.coroutines.JobCancellationException istisna atılacaktır. İstisnayı yakalayabilir ve biraz temizlik yapabilirsiniz.

currentJob = viewModelScope.launch {
    try {
        val job1 = launch {
            ...
        }

        val job2 = launch {
            ...
        }

        job1.join()
        job2.join()

    } catch (e: Exception) {
        
        currentJob = null
    }    
}

kotlinx.coroutines.coroutineContext

Eşyordamı ayıklamak için, günlüğe kaydetme en kolay yoldur. kotlinx.coroutines.coroutineContext oturum açmak için çok kullanışlıdır. Eşyordam ve iş parçacığı bilgilerini sağlar.

Lütfen bunun yalnızca askıya alma işlevinden çağrılabilen bir askıya alma özelliği olduğunu unutmayın.

Nın bir örneği Utils.log() sarmak için yardımcı programı askıya alma işlevi .Log.d():

object Utils {  
    suspend fun log(tag: String, msg: String) {  
        Log.d(tag, "$coroutineContext: $msg")  
    }  
}


Utils.log("ViewModel", "======= Created launch coroutine - onButtonClick() =======")

Logcat çıktısı örneği:

D/ViewModel: [StandaloneCoroutine{Active}@5261b32, Dispatchers.Main.immediate]: ======= Created launch coroutine - onButtonClick() =======

Bazı düşünceler

Şimdiye kadar, tüm benim Kişisel projeler yukarıdaki tüm eşyordam kullanım durumlarını kullanmayın. sadece kullanırım CoroutineScope.launch ve CoroutineScope.withContext() bu da istediğimi elde etmem için yeterli. Bir eşyordamı iptal etmem bile gerekmiyor, ancak istersem yapabilirim ve uygulamalar hala mükemmel çalışıyor.

[Update: April 13, 2022]: kullandım joinAll() kodu sırayla çalıştırmak yerine birkaç ağ aramasını paralel hale getirin. Aşağıdaki örnek:

private suspend fun fetchArticlesFeed() : List<ArticleFeed> = coroutineScope {
    val results = mutableListOf<ArticleFeed>()
    val jobs = mutableListOf<Job>()

    for(url in urls) {
        val job = launch {
            val xmlString = webService.getXMlString(url)
            val articleFeeds = FeedParser().parse(xmlString)
            results.addAll(articleFeeds)
        }

        jobs.add(job)
    }

    jobs.joinAll()

    return@coroutineScope results
}

Kaynak kodu

GitHub Deposu: Demo_CoroutinesTemel Bilgiler

Ayrıca bakınız

İlgili Makaleler

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Başa dön tuşu