Kotlin eş yordamlarıyla uygulama performansını iyileştirme

Kotlin eş yordamları kolay bir zaman çizelgesi kullanan net, basitleştirilmiş Ağ çağrıları gibi uzun süreli görevleri yönetirken uygulamanız hızlı yanıt veriyor veya disk işlemleri için de geçerlidir.

Bu konuda, Android'deki eş yordamlara ayrıntılı bir bakış sunulmaktadır. Eğer eş yordamlar hakkında bilginiz yoksa, Bu konuyu okumadan önce Android'de Kotlin eş yordamları başlıklı makaleyi okuyun.

Uzun süreli görevleri yönetin

Eş yordamlar, işlenecek iki işlem eklenerek normal fonksiyonlar üzerine kurulur uzun süre devam eden görevlerdir. invoke (veya call) ve return ek olarak eş yordamlar suspend ve resume değerlerini ekler:

  • suspend, geçerli eş yordamın yürütülmesini duraklatarak tüm yerel verileri kaydeder değişkenlerine karşılık gelir.
  • resume, ilgili yerden askıya alınmış bir eş yordamın yürütülmesine devam ediyor askıya alınır.

suspend işlevlerini yalnızca diğer suspend işlevlerinden çağırabilir veya yeni bir eş yordam başlatmak için launch gibi bir eş yordam oluşturucu kullanarak.

Aşağıdaki örnekte bir uzun süren varsayıma dayalı bir görev:

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

suspend fun get(url: String) = withContext(Dispatchers.IO) { /* ... */ }

Bu örnekte, get() ana iş parçacığında çalışmaya devam eder ancak koordinasyonunu gerektirir. Ağ isteği işlemi tamamlandığında get, geri çağırma yerine askıya alınmış eş yordamı devam ettirir ileti dizisine bildirim gönderilir.

Kotlin, hangi işlevin birlikte çalıştığını yönetmek için bir yığın çerçevesi kullanır kullanabilirsiniz. Bir eş yordamı askıya alırken geçerli yığın kare kopyalanıp daha sonra kullanılmak üzere kaydedilir. Devam ettirildiğinde yığın çerçevesi kaydedildiği yerden geri kopyalanır ve işlev yeniden çalışmaya başlar. Kod, sıradan bir sıralı engelleme gibi görünse de eş yordam, ağ isteğinin engellenmemesini sağladığından takip edebilirsiniz.

Ana güvenlik için eş yordamlar kullan

Kotlin eş yordamları, hangi iş parçacıklarının kullanıldığını belirlemek için görev dağıtıcılarını kullanır eş yordam yürütme. Ana iş parçacığının dışında kod çalıştırmak için Kotlin'e Varsayılan veya IO sevk görevlisinde çalışmak için eş yordamlardan birini kullanın. İçinde Kotlin, tüm eş yordamlar bir görev dağıtıcıda takip edebilirsiniz. Eş yordamlar kendilerini askıya alabilir ve sevk görevlisi devam ettirmekten sorumludur.

Kotlin, eş yordamların nerede çalıştırılması gerektiğini belirtmek için üç görev dağıtıcı sağlar. şunları kullanabilirsiniz:

  • Sispatchers.Main - Ana hat üzerinde bir eş yordam çalıştırmak için bu görev dağıtıcıyı kullanın Android iş parçacığı. Bu, yalnızca kullanıcı arayüzüyle etkileşimde bulunmak ve yardımcı olan ekip çalışmasıdır. Örnek olarak suspend işlevlerini çağırma, Android kullanıcı arayüzü çerçeve işlemleri ve güncelleme LiveData nesne.
  • Dispatchers.IO - Bu görev dağıtıcı, disk veya ağ gerçekleştirmek için optimize edilmiştir Ana iş parçacığının dışında G/Ç. Örnek olarak, Oda bileşeni, dosyalardan okuma veya dosyalara yazma ve ağ işlemlerini çalıştırma.
  • Dispatchers.Default - Bu sevk görevlisi şu amaçlar için optimize edilmiştir: Ana iş parçacığının dışında CPU'yu yoğun şekilde kullanan iş. Örnek kullanım alanları arasında JSON'u listelemek ve ayrıştırmaktır.

Önceki örnekten devam edersek, görevleri yeniden tanımlamak için sevk görevlilerini get işlevi. get gövdesinin içinde withContext(Dispatchers.IO) öğesini şunun için çağırın: KS iş parçacığı havuzunda çalışan bir blok oluşturun. Bunun içine yerleştirdiğiniz bloku her zaman IO sevk görevlisi aracılığıyla yürütülür. withContext kendisinin bir askıya alma işlevi için, get işlevi de bir askıya alma işlevidir.

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
}

Eş yordamlar sayesinde, ileti dizilerini ayrıntılı denetimle gönderebilirsiniz. Çünkü withContext(), herhangi bir kod satırının iş parçacığı havuzunu kullanıma sunduk. Bunları, okuma gibi çok küçük işlevlere ağ isteği gerçekleştirir. Her işlevin ana güvenli olduğundan emin olmak için withContext(). Bu, ana iş parçacığından işlevi çağırabilir. Böylece, arayan kişinin işlevi yürütmek için hangi iş parçacığının kullanılması gerektiğini düşünün.

Yukarıdaki örnekte, fetchDocs() ana iş parçacığında yürütülür; ancak Arka planda ağ isteği gerçekleştiren get numaralı telefonu güvenli bir şekilde çağırabilir. Eş yordamlar suspend ve resume, yani ana sayfadaki eş yordamı desteklediği için withContext bloğu olduğu anda ileti dizisi get sonucuyla devam ettirilir tamamlandı.

withContext() performansı

withContext() geri çağırmaya dayalı eşdeğer bir modele kıyasla fazladan hakkında bilgi edindiniz. Dahası, withContext() çağrılarını optimize etmek mümkündür bazı durumlarda geri çağırmaya dayalı eşdeğer bir uygulamanın ötesine geçer. Örneğin, Örneğin, bir işlev bir ağa on çağrıda bulunursa, Kotlin'e Bir dış withContext() kullanarak ileti dizilerini yalnızca bir kez değiştirin. Sonra, ağ kitaplığı withContext() öğesini birden çok kez kullandığı halde aynı kalır ileti dizileri arasında geçiş yapmaktan kaçınır. Bunun yanı sıra Kotlin, dönüşüm hunisinin İleti dizisi değiştirmelerini önlemek için Dispatchers.Default ile Dispatchers.IO arasında kullanmanızı öneririz.

Eş yordam başlat

Eş yordamları iki şekilde başlatabilirsiniz:

  • launch yeni bir eş yordam başlatır ve sonucu arayana döndürmez. Herhangi biri kabul edilen bir iş ise launch kullanılarak başlatılabilir.
  • async yeni bir eş yordam başlatır ve askıya alınmış bir sonuç döndürmenizi sağlar işlevi (await) kullanır.

Genellikle, normal bir işlevden yeni bir eş yordam launch gibi bir normal fonksiyon await yöntemini çağıramaz. async öğesini yalnızca içerideyken kullanın başka bir eş yordamda veya askıya alma işlevi içindeyken yardımcı olur.

Paralel ayrıştırma

suspend işlevi içinde başlatılan tüm eş yordamlar bu işlevin döndürüldüğünden, muhtemelen bu eş yordamların geri dönmeden önce bitirin. Kotlin'deki yapılandırılmış eşzamanlılık ile, bir veya daha fazla eş yordam başlatan bir coroutineScope. Ardından await() ile (tek bir eş yordam için) veya awaitAll() (birden çok eş yordam için) için bu eş yordamların işlevden dönmeden önce tamamlanmasını garanti eder.

Örnek olarak, iki doküman getiren bir coroutineScope tanımlayalım. eşzamansız olarak ayarlayabilirsiniz. Her ertelenmiş referans için await() numaralı telefonu arayarak şunları garanti ederiz: her iki async işleminin de bir değer döndürmeden önce bitmesini sağlar:

suspend fun fetchTwoDocs() =
    coroutineScope {
        val deferredOne = async { fetchDoc(1) }
        val deferredTwo = async { fetchDoc(2) }
        deferredOne.await()
        deferredTwo.await()
    }

Aşağıdaki örnekte gösterildiği gibi, awaitAll() öğesini koleksiyonlarda da kullanabilirsiniz:

suspend fun fetchTwoDocs() =        // called on any Dispatcher (any thread, possibly Main)
    coroutineScope {
        val deferreds = listOf(     // fetch two docs at the same time
            async { fetchDoc(1) },  // async returns a result for the first doc
            async { fetchDoc(2) }   // async returns a result for the second doc
        )
        deferreds.awaitAll()        // use awaitAll to wait for both network requests
    }

fetchTwoDocs(), async ile yeni eş yordamlar kullanıma sunsa da işlev önce, başlatılan eş yordamların tamamlanmasını beklemek için awaitAll() kullanıyor geri dönüyor. Ancak, awaitAll() adlı kullanıcıyı çağırmamış olsak bile, coroutineScope derleyici, tüm yeni eş yordamlar tamamlanana kadar fetchTwoDocs.

Ayrıca, coroutineScope, eş yordamların gönderdiği istisnaları da yakalar arayana yönlendirir.

Paralel ayrıştırma hakkında daha fazla bilgi için bkz. Askıya alma işlevleri oluşturma.

Eş yordam kavramları

Eş yordam

CoroutineScope launch veya async kullanarak oluşturduğu eş yordamları takip eder. İlgili içeriği oluşturmak için kullanılan devam eden işler (ör. çalışan eş yordamlar) scope.cancel(). Android'de, bazı KTX kitaplıkları belirli yaşam döngüsü sınıfları için kendi CoroutineScope kullanıyor. Örneğin, ViewModel bir viewModelScope, ve Lifecycle için lifecycleScope kullanılıyor. Ancak CoroutineScope, bir sevk görevlisinden farklı olarak eş yordamları çalıştırmaz.

viewModelScope, şurada bulunan örneklerde de kullanılır: Android'de eş yordamlarla arka plan ileti dizisi oluşturma. Ancak, CoroutineScope eş yordamların yaşam döngüsünü takip etmek için şu şekilde:

class ExampleClass {

    // Job and Dispatcher are combined into a CoroutineContext which
    // will be discussed shortly
    val scope = CoroutineScope(Job() + Dispatchers.Main)

    fun exampleMethod() {
        // Starts a new coroutine within the scope
        scope.launch {
            // New coroutine that can call suspend functions
            fetchDocs()
        }
    }

    fun cleanUp() {
        // Cancel the scope to cancel ongoing coroutines work
        scope.cancel()
    }
}

İptal edilen bir kapsam daha fazla eş yordam oluşturamaz. Dolayısıyla, scope.cancel() öğesini yalnızca yaşam döngüsünü kontrol eden sınıf olduğunda çağır imha ediliyor. viewModelScope kullanılırken ViewModel sınıfı şunu iptal eder: kapsamını ViewModel'in onCleared() yönteminde otomatik olarak uygular.

İş

Job eş yordamın herkese açık kullanıcı adı. launch ile oluşturduğunuz her eş yordam veya async,Job eş yordamını bozar ve yaşam döngüsünü yönetir. Ayrıca, şuraya Job aktarabilirsiniz: Aşağıdaki gösterildiği gibi yaşam döngüsünü daha da yönetmek için CoroutineScope örnek:

class ExampleClass {
    ...
    fun exampleMethod() {
        // Handle to the coroutine, you can control its lifecycle
        val job = scope.launch {
            // New coroutine
        }

        if (...) {
            // Cancel the coroutine started above, this doesn't affect the scope
            // this coroutine was launched in
            job.cancel()
        }
    }
}

Eş yordam

CoroutineContext aşağıdaki öğe kümesini kullanarak bir eş yordamın davranışını tanımlar:

Bir kapsam içinde oluşturulan yeni eş yordamlar için yeni bir Job örneği koordine ve diğer CoroutineContext öğelerine atandı öğeleri kapsayıcı kapsamdan devralınır. Devralınan launch veya async öğesine yeni bir CoroutineContext ileterek öğeleri işlevini kullanın. launch veya async öğesine Job iletmenin herhangi bir etkisi olmadığını unutmayın. yeni bir Job örneği olarak her zaman yeni bir eş yordama atanır.

class ExampleClass {
    val scope = CoroutineScope(Job() + Dispatchers.Main)

    fun exampleMethod() {
        // Starts a new coroutine on Dispatchers.Main as it's the scope's default
        val job1 = scope.launch {
            // New coroutine with CoroutineName = "coroutine" (default)
        }

        // Starts a new coroutine on Dispatchers.Default
        val job2 = scope.launch(Dispatchers.Default + CoroutineName("BackgroundCoroutine")) {
            // New coroutine with CoroutineName = "BackgroundCoroutine" (overridden)
        }
    }
}

Ek eş yordam kaynakları

Diğer eş yordam kaynakları için aşağıdaki bağlantılara bakın: