Yaşam döngüsüne duyarlı bileşenlerle Kotlin eş yordamlarını kullanın

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:

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

ziyaret edin. ziyaret edin.