Eşzamanlı bir eş zamanlılık tasarım kalıbıdır. Bu yapıda Android'in eşzamansız olarak çalışan kodları basitleştirmesi. Koordinler 1.3 sürümünde Kotlin'e eklenmiştir ve diğer dillerdeki kavramlar olabilir.
Android'de eş yordamlar, gerçekleşebilecek uzun süreli görevlerin aksi takdirde ana iş parçacığını engeller ve uygulamanızın yanıt vermemesine neden olur. Eş yordam kullanan profesyonel geliştiricilerin% 50'den fazlası, verimlilik artışı sağlar. Bu bölümde, bu sorunları ele almak için Kotlin eş yordamlarını nasıl kullanabileceğiniz açıklanmaktadır. Böylece daha net ve kısa ve öz uygulama kodu yazabilirsiniz.
Özellikler
Eş yordamlar, Android Önemli özelliklerden bazıları şunlardır:
- Hafif: şunun için destek: askıya alma, eş yordamın çalıştırıldığı iş parçacığını engellemez. Askıya alınıyor birçok eşzamanlı işlemi desteklerken engelleme sırasında bellek tasarrufu sağlar.
- Daha az bellek sızıntısı: yapılandırılmış eşzamanlılık pek çok farklı yolu vardır.
- Yerleşik iptal desteği: İptal çalışan eş hatlı hiyerarşide otomatik olarak yayılır.
- Jetpack entegrasyonu: Çoğu Jetpack kitaplığı tam eş yordam desteği sağlayan uzantılar. Biraz kütüphaneler ayrıca kendi eşdeğer kapsam yapılandırılmış eş zamanlılık için de kullanılıyor.
Örneklere genel bakış
Uygulama mimarisi rehberi doğrultusunda bir ağ isteğinde bulunun ve sonucu ana makineye döndürün iş parçacığı (burada uygulama daha sonra sonucu kullanıcıya gösterebilir).
Daha ayrıntılı belirtmek gerekirse, ViewModel
Mimari bileşeni, ana iş parçacığındaki depo katmanını
ağ isteğini tetikler. Bu kılavuz, çeşitli çözümlerle aynıdır.
eş yordamlar kullanan başka etiketler de oluşturabilirsiniz.
ViewModel
, doğrudan
eş yordamlar. Bu uzantılar
lifecycle-viewmodel-ktx
kitaplığı ve kullanılıyor
inceleyebilirsiniz.
Bağımlılık bilgisi
Android projenizde eş yordamlar kullanmak için aşağıdaki bağımlılığı ekleyin
(uygulamanızın build.gradle
dosyasına):
Eski
dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' }
Kotlin
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9") }
Bir arka plan iş parçacığında yürütülüyor
Ana iş parçacığında bir ağ isteğinde bulunmak, ağ isteğinin beklemesine veya engellenmesine neden olur.
yanıt alana kadar devam eder. İleti dizisi engellendiği için
onDraw()
çağırabiliyor. Bu da uygulamanızın donmasına neden olabilir.
Uygulama Yanıt Vermiyor (ANR) iletişim kutusuna yönlendirir. Daha iyi bir kullanıcı için
bu işlemi bir arka plan iş parçacığı üzerinde çalıştıralım.
İlk olarak Repository
dersimize bakalım ve nasıl bir deneyim olduğunu öğrenelim
ağ isteğinde bulunun:
sealed class Result<out R> {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
}
class LoginRepository(private val responseParser: LoginResponseParser) {
private const val loginUrl = "https://example.com/login"
// Function that makes the network request, blocking the current thread
fun makeLoginRequest(
jsonBody: String
): Result<LoginResponse> {
val url = URL(loginUrl)
(url.openConnection() as? HttpURLConnection)?.run {
requestMethod = "POST"
setRequestProperty("Content-Type", "application/json; utf-8")
setRequestProperty("Accept", "application/json")
doOutput = true
outputStream.write(jsonBody.toByteArray())
return Result.Success(responseParser.parse(inputStream))
}
return Result.Error(Exception("Cannot open HttpURLConnection"))
}
}
makeLoginRequest
eşzamanlı ve görüşme dizisini engelliyor. Model oluşturmak için
için kendi Result
sınıfımızı oluşturuyoruz.
ViewModel
, kullanıcı reklam öğesini tıkladığında ağ isteğini tetikler.
bir düğme üzerinde:
class LoginViewModel(
private val loginRepository: LoginRepository
): ViewModel() {
fun login(username: String, token: String) {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
loginRepository.makeLoginRequest(jsonBody)
}
}
Önceki kodda, LoginViewModel
aşağıdaki durumlarda kullanıcı arayüzü ileti dizisini engelliyor.
. Yürütmeyi taşımak için en basit çözüm
ana iş parçacığının dışında yeni bir eş yordam oluşturup ağı yürütmektir.
bir G/Ç iş parçacığında istek:
class LoginViewModel(
private val loginRepository: LoginRepository
): ViewModel() {
fun login(username: String, token: String) {
// Create a new coroutine to move the execution off the UI thread
viewModelScope.launch(Dispatchers.IO) {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
loginRepository.makeLoginRequest(jsonBody)
}
}
}
login
fonksiyonunda eş yordam kodunu inceleyelim:
viewModelScope
,CoroutineScope
ViewModel
KTX uzantısı var. Tüm eş yordamların kapsam.CoroutineScope
bir veya daha fazla ilgili eş yordamı yönetir.launch
, eş yordam oluşturan ve ilgili sevk görevlisine iletmesini sağlamak.Dispatchers.IO
, bu eş yordamın iş parçacığı G/Ç işlemleri için ayrılmış.
login
işlevi şu şekilde yürütülür:
- Uygulama, ana iş parçacığındaki
View
katmanındanlogin
işlevini çağırır. launch
yeni bir eş yordam oluşturur ve ağ isteği yapılır için ayrılmış bir iş parçacığında bağımsız olarak oluşturulur.- Eş yordam çalışırken
login
işlevi yürütmeye devam eder büyük olasılıkla ağ isteği tamamlanmadan önce döner. Lütfen ağ yanıtı şimdilik yoksayılmaktadır.
Bu eş yordam viewModelScope
ile başladığından
ViewModel
kapsamına girer. ViewModel
kullanıcı ekrandan ayrılıyorsa viewModelScope
otomatik olarak
ve çalışan tüm eş yordamlar da iptal edilir.
Önceki örnekteki sorunlardan biri,
makeLoginRequest
, yürütmeyi açıkça devre dışı bırakmayı hatırlaması gerekir
takip edebilirsiniz. Repository
öğesini değiştirerek nasıl çözebileceğimize bakalım.
çözmüştük.
Ana güvenlik için eş yordamlar kullan
main-safe,
iş parçacığı. makeLoginRequest
işlevi ana güvenli değil, çünkü çağrı
Ana iş parçacığındaki makeLoginRequest
, kullanıcı arayüzünü engelliyor. Şunu kullanın:
Yürütmeyi taşımak için eş yordamlar kitaplığından withContext()
işlevi
farklı bir iş parçacığına dönüştürme:
class LoginRepository(...) {
...
suspend fun makeLoginRequest(
jsonBody: String
): Result<LoginResponse> {
// Move the execution of the coroutine to the I/O dispatcher
return withContext(Dispatchers.IO) {
// Blocking network request code
}
}
}
withContext(Dispatchers.IO)
, eş yordamın yürütülmesini bir
I/O iş parçacığı, çağrı işlevimizi ana güvenli hale getirir ve kullanıcı arayüzünün
gerektiği şekilde güncelleyin.
makeLoginRequest
, suspend
anahtar kelimesiyle de işaretlenmiş. Bu anahtar kelime
Kotlin'in, eş yordam içinden çağrılacak bir işlevi zorunlu kılma yöntemidir.
Aşağıdaki örnekte, eş yordam LoginViewModel
içinde oluşturulmuştur.
makeLoginRequest
, yürütmeyi ana iş parçacığının dışına taşırken eş yordam,
login
işlevindeki öğeler artık ana iş parçacığında yürütülebilir:
class LoginViewModel(
private val loginRepository: LoginRepository
): ViewModel() {
fun login(username: String, token: String) {
// Create a new coroutine on the UI thread
viewModelScope.launch {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
// Make the network call and suspend execution until it finishes
val result = loginRepository.makeLoginRequest(jsonBody)
// Display result of the network request to the user
when (result) {
is Result.Success<LoginResponse> -> // Happy path
else -> // Show error in UI
}
}
}
}
makeLoginRequest
değeri olduğundan eş yordamın burada da gerekli olduğunu unutmayın
bir suspend
işlevi olmalı ve tüm suspend
işlevleri
eş yordam.
Bu kod, önceki login
örneğinden birkaç açıdan farklıdır:
launch
,Dispatchers.IO
parametresini almaz. Bunu yaptığınızdalaunch
konumunaDispatcher
aktarmak için,viewModelScope
ana iş parçacığında çalışıyor.- Ağ isteğinin sonucu, başarıyı göstermek için artık işlenir. kullanıcı arayüzü.
Giriş işlevi artık şu şekilde yürütülmektedir:
- Uygulama, ana iş parçacığındaki
View
katmanındanlogin()
işlevini çağırır. launch
, ana iş parçacığında yeni bir eş yordam oluşturur ve eş yordam başlar birkaç adım var.- Eş yordam içinde,
loginRepository.makeLoginRequest()
çağrısı artık eş yordamın yürütülmesiwithContext
tarihine kadar askıya alınıyormakeLoginRequest()
içindeki bloğun çalışması tamamlanacak. withContext
bloku tamamlandığındalogin()
içindeki eş yordam devam eder ağ isteğinin sonucuyla birlikte ana iş parçacığında yürütme.
İstisnaları işleme
Repository
katmanının atabileceği istisnaları işlemek için Kotlin katmanını kullanın
istisnalar için yerleşik destek.
Aşağıdaki örnekte try-catch
bloğu kullanılmıştır:
class LoginViewModel(
private val loginRepository: LoginRepository
): ViewModel() {
fun login(username: String, token: String) {
viewModelScope.launch {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
val result = try {
loginRepository.makeLoginRequest(jsonBody)
} catch(e: Exception) {
Result.Error(Exception("Network request failed"))
}
when (result) {
is Result.Success<LoginResponse> -> // Happy path
else -> // Show error in UI
}
}
}
}
Bu örnekte, makeLoginRequest()
tarafından atılan beklenmedik bir istisna
çağrısı, kullanıcı arayüzünde hata olarak işlenir.
Ek eş yordam kaynakları
Android'deki eş yordamlara daha ayrıntılı bir bakış için Kotlin eş yordamlarıyla uygulama performansını iyileştirin.
Diğer eş yordam kaynakları için aşağıdaki bağlantılara bakın:
- Koordinlere genel bakış (JetBrains)
- Koordinat rehberi (JetBrains)
- Kotlin eş yordamları ve akışı için ek kaynaklar