Kotlin eş yordamları, aşağıdakileri yazmanıza olanak tanıyan bir API sunar:
eşzamansız koddur. Kotlin eş yordamlarıyla, bir
CoroutineScope
Bu, eş yordamlarınızın ne zaman çalışacağını yönetmenize yardımcı olur. Her bir eşzamansız
belirli bir kapsamda çalışır.
Yaşam döngüsüne duyarlı bileşenler
uygulamanızda mantıksal kapsamlar için eş yordamlar için birinci sınıf destek ve
LiveData
ile birlikte çalışabilirlik katmanı.
Bu konuda, eş yordamların yaşam döngüsüne duyarlı özelliklerle etkili bir şekilde nasıl kullanılacağı açıklanmaktadır.
bileşenlerine ayıralım.
KTX bağımlılıkları ekleme
Bu konuda açıklanan yerleşik eş değer kapsamlar İlgili her bileşen için KTX uzantıları. Bu seçeneği eklediğinizden emin olun ve uygun bağımlılıkları belirlemenize yardımcı olur.
ViewModelScope
için şunu kullanın:androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0
veya daha yüksek.LifecycleScope
için şunu kullanın:androidx.lifecycle:lifecycle-runtime-ktx:2.4.0
veya daha yüksek.liveData
için şunu kullanın:androidx.lifecycle:lifecycle-livedata-ktx:2.4.0
veya daha yüksek.
Yaşam döngüsüne duyarlı eş yordam kapsamları
Yaşam döngüsüne duyarlı bileşenler, kullanabileceğiniz aşağıdaki yerleşik kapsamları tanımlar dokunun.
GörünümModelKapsamı
Her biri için bir ViewModelScope
Uygulamanızda ViewModel
. Herhangi biri
ViewModel
temizlenir. Eş yordamlar, tamamlanması gereken bir işin olduğunda
yalnızca ViewModel
etkinse yapılır. Örneğin, projenizin
başarı kriterlerini
verilerinizi bir düzene göre düzenlerseniz, çalışmaların kapsamını ViewModel
ViewModel
temizlendi, tüketimi önlemek için iş otomatik olarak iptal edildi
kaynaklar.
ViewModel
öğesinin CoroutineScope
bölümüne şuradan erişebilirsiniz:
Aşağıdaki örnekte gösterildiği gibi ViewModel'in viewModelScope
özelliği:
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
Yaşam Döngüsü Kapsamı
Her biri için bir LifecycleScope
Lifecycle
nesnesini ifade eder. Herhangi bir eş yordam
Lifecycle
kaldırıldığında bu kapsamdaki başlatma işlemi iptal edilir. Şunları yapabilirsiniz:
Lifecycle
öğesinin CoroutineScope
bölümüne şu yolla erişin:
lifecycle.coroutineScope
veya lifecycleOwner.lifecycleScope
mülkleri.
Aşağıdaki örnekte, lifecycleOwner.lifecycleScope
işlevinin nasıl kullanılacağı gösterilmektedir
önceden hesaplanmış metni eşzamansız olarak oluşturma:
class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
val params = TextViewCompat.getTextMetricsParams(textView)
val precomputedText = withContext(Dispatchers.Default) {
PrecomputedTextCompat.create(longTextContent, params)
}
TextViewCompat.setPrecomputedText(textView, precomputedText)
}
}
}
Yeniden başlatılabilir yaşam döngüsüne duyarlı eş yordamlar
lifecycleScope
, iptal için uygun bir yol sunsa da
Lifecycle
DESTROYED
olduğunda uzun süreli işlemler otomatik olarak
bir kodu yürütmeye başlamak istediğiniz başka durumlarınız da olabilir.
Lifecycle
belirli bir durumda olduğunda engelle ve seçili olduğunda iptal et
başka bir eyalet. Örneğin, bir akış toplamak isteyebilirsiniz.
Lifecycle
STARTED
ve STOPPED
olduğunda koleksiyonu iptal edin. Bu
yalnızca kullanıcı arayüzü ekranda görünür olduğunda akış emisyonlarını
kaynak tasarrufu sağlayabilir ve uygulama kilitlenmelerini önleyebilir.
Bu durumlarda Lifecycle
ve LifecycleOwner
, askıya alma özelliğini sağlar
repeatOnLifecycle
API tam olarak bunu yapıyor. Aşağıdaki örnekte bir
ilişkilendirilmiş Lifecycle
en az
STARTED
durumu, Lifecycle
STOPPED
olduğunda iptal edilir:
class MyFragment : Fragment() {
val viewModel: MyViewModel by viewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Create a new coroutine in the lifecycleScope
viewLifecycleOwner.lifecycleScope.launch {
// repeatOnLifecycle launches the block in a new coroutine every time the
// lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
// Trigger the flow and start listening for values.
// This happens when lifecycle is STARTED and stops
// collecting when the lifecycle is STOPPED
viewModel.someDataFlow.collect {
// Process item
}
}
}
}
}
Yaşam döngüsüne duyarlı akış toplama
Yalnızca tek bir akışta yaşam döngüsüne duyarlı toplama gerçekleştirmeniz gerekiyorsa şunları yapabilirsiniz:
her bir arama terimi için
Flow.flowWithLifecycle()
yöntemini kullanabilirsiniz:
viewLifecycleOwner.lifecycleScope.launch {
exampleProvider.exampleFlow()
.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED)
.collect {
// Process the value.
}
}
Ancak birden fazla akışta yaşam döngüsüne duyarlı toplama gerçekleştirmeniz gerekiyorsa
her akışı farklı eş yordamlarda toplamanız gerekir. Böyle bir durumda,
doğrudan repeatOnLifecycle()
kullanmak daha verimlidir:
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
// Because collect is a suspend function, if you want to
// collect multiple flows in parallel, you need to do so in
// different coroutines.
launch {
flow1.collect { /* Process the value. */ }
}
launch {
flow2.collect { /* Process the value. */ }
}
}
}
Yaşam döngüsüne duyarlı eş yordamları askıya al
CoroutineScope
, iptal için uygun bir yol sunsa da
uzun süreli işlemleri otomatik olarak yapmak istiyorsanız
Lifecycle
değeri belirli bir değer olmadığı sürece bir kod bloğunun yürütülmesini askıya almak
durumu. Örneğin, bir FragmentTransaction
çalıştırmak için
Lifecycle
en az STARTED
. Bu durumlarda Lifecycle
,
ek yöntemler: lifecycle.whenCreated
, lifecycle.whenStarted
ve
lifecycle.whenResumed
. Bu blokların içindeki eş yordamlar şu durumlarda askıya alınır:
Lifecycle
, istenen minimum durumda değil.
Aşağıdaki örnekte, yalnızca
Lifecycle
en az STARTED
durumunda:
class MyFragment: Fragment {
init { // Notice that we can safely launch in the constructor of the Fragment.
lifecycleScope.launch {
whenStarted {
// The block inside will run only when Lifecycle is at least STARTED.
// It will start executing when fragment is started and
// can call other suspend methods.
loadingView.visibility = View.VISIBLE
val canAccess = withContext(Dispatchers.IO) {
checkUserAccess()
}
// When checkUserAccess returns, the next line is automatically
// suspended if the Lifecycle is not *at least* STARTED.
// We could safely run fragment transactions because we know the
// code won't run unless the lifecycle is at least STARTED.
loadingView.visibility = View.GONE
if (canAccess == false) {
findNavController().popBackStack()
} else {
showContent()
}
}
// This line runs only after the whenStarted block above has completed.
}
}
}
Bir eş yordam varken Lifecycle
aracı
when
yöntem kullanıldığında eş yordam otomatik olarak iptal edilir. Aşağıdaki örnekte,
Lifecycle
durumu DESTROYED
olduğunda finally
bloğu çalışır:
class MyFragment: Fragment {
init {
lifecycleScope.launchWhenStarted {
try {
// Call some suspend functions.
} finally {
// This line might execute after Lifecycle is DESTROYED.
if (lifecycle.state >= STARTED) {
// Here, since we've checked, it is safe to run any
// Fragment transactions.
}
}
}
}
}
LiveData ile eş yordamları kullanma
LiveData
kullanırken aşağıdakilere ihtiyacınız olabilir:
kullanarak değerleri eşzamansız olarak hesaplayabilirsiniz. Örneğin, ekip arkadaşlarınızın
ve bunları kullanıcı arayüzünüze
sunabilirsiniz. İçinde
bu durumlarda suspend
çağrısı yapmak için liveData
oluşturucu işlevini kullanabilirsiniz
işlevinden birini çağırarak sonuç LiveData
nesnesi olarak sunulur.
Aşağıdaki örnekte loadUser()
, başka bir yerde beyan edilen bir askıya alma işlevidir. Tekliflerinizi otomatikleştirmek ve optimize etmek için
loadUser()
öğesini eşzamansız olarak çağırmak için liveData
derleyici işlevini kullanın ve ardından
sonucu çıkarmak için emit()
ifadesini kullanın:
val user: LiveData<User> = liveData {
val data = database.loadUser() // loadUser is a suspend function.
emit(data)
}
liveData
yapı taşı, bir görevi
yapılandırılmış eşzamanlılık temel öğesi
eş yordamlar ile LiveData
arasında. Kod bloğu aşağıdaki durumlarda yürütülmeye başlar:
LiveData
, yapılandırılabilir bir ayardan sonra etkin hale gelir ve otomatik olarak iptal edilir.
LiveData
devre dışı bırakıldığında zaman aşımına uğrar. Daha önce iptal edilmişse
LiveData
tekrar etkinleştiğinde yeniden başlatılır. Eğer
başarılı bir şekilde tamamlanırsa program yeniden başlatılmaz. Lütfen
yalnızca otomatik olarak iptal edilirse yeniden başlatılır. Engelleme işlemi diğer
bir nedenden dolayı (ör. CancellationException
fırladığında) başlatma yeniden başlatılmaz.
Ayrıca bloktan birden fazla değer de yayınlayabilirsiniz. Her emit()
çağrısı askıya alınır
LiveData
değeri ana iş parçacığında ayarlanana kadar engellemenin yürütülmesi.
val user: LiveData<Result> = liveData {
emit(Result.loading())
try {
emit(Result.success(fetchUser()))
} catch(ioException: Exception) {
emit(Result.error(ioException))
}
}
Ayrıca liveData
öğesini şununla birleştirebilirsiniz:
Transformations
, gösterildiği gibi
aşağıdaki örneği inceleyin:
class MyViewModel: ViewModel() {
private val userId: LiveData<String> = MutableLiveData()
val user = userId.switchMap { id ->
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
emit(database.loadUserById(id))
}
}
}
emitSource()
öğesini çağırarak bir LiveData
öğesinden birden fazla değer yayınlayabilirsiniz.
işlevini kullanabilirsiniz. emit()
için yapılan her çağrının
veya emitSource()
daha önce eklenen kaynağı kaldırır.
class UserDao: Dao {
@Query("SELECT * FROM User WHERE id = :id")
fun getUser(id: String): LiveData<User>
}
class MyRepository {
fun getUser(id: String) = liveData<User> {
val disposable = emitSource(
userDao.getUser(id).map {
Result.loading(it)
}
)
try {
val user = webservice.fetchUser(id)
// Stop the previous emission to avoid dispatching the updated user
// as `loading`.
disposable.dispose()
// Update the database.
userDao.insert(user)
// Re-establish the emission with success type.
emitSource(
userDao.getUser(id).map {
Result.success(it)
}
)
} catch(exception: IOException) {
// Any call to `emit` disposes the previous one automatically so we don't
// need to dispose it here as we didn't get an updated value.
emitSource(
userDao.getUser(id).map {
Result.error(exception, it)
}
)
}
}
}
Eş yordamlarla ilgili daha fazla bilgi için aşağıdaki bağlantılara bakın:
- Kotlin eş yordamlarıyla uygulama performansını iyileştirme
- Corutinlere genel bakış
- CooutineWorker'da ileti dizisi oluşturma
Ek kaynaklar
Yaşam döngüsüne duyarlı bileşenlerle eş yordamlar kullanma hakkında daha fazla bilgi edinmek için şu sayfaya bakın: inceleyebilirsiniz.
Örnekler
Bloglar
- Android'de eş yordamlar: Uygulama kalıpları
- Android'de kolay eş yordamlar: viewModelScope
- Art arda iki LiveData emisyonunu eş yordamlarla test etme
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- LiveData'ya genel bakış
- Yaşam Döngüsüne Duyarlı Bileşenlerle Yaşam Döngülerini Yönetme
- Sayfalandırılmış verileri yükleme ve görüntüleme