La rutina de Kotlin y el resumen de uso en Android (dos componentes de la arquitectura Jetpack se usan juntos)

Inserte la descripción de la imagen aquí

En Android, se recomienda oficialmente usar con componentes de arquitectura Jetpack

(1) Introducción de corutinas

  • implementación 'org.jetbrains.kotlinx: kotlinx-coroutines-android: 1.3.3'

(2) Introducir la extensión KTX de los componentes de la arquitectura Jetpack

  • Para ViewModelScope, use androidx.lifecycle: lifecycle-viewmodel-ktx: 2.1.0-beta01 o superior.
  • Para LifecycleScope, utilice androidx.lifecycle: lifecycle-runtime-ktx: 2.2.0-alpha01 o superior.
  • Para liveData, use androidx.lifecycle: lifecycle-livedata-ktx: 2.2.0-alpha01 o superior.

ViewModelScope

Cada ViewModel en la aplicación define un ViewModelScope. Si se borra el ViewModel, las rutinas iniciadas en este rango se cancelarán automáticamente. Si tiene trabajo que debe hacerse solo cuando ViewModel está activo, las corutinas son muy útiles en este momento. Por ejemplo, si desea calcular algunos datos para el diseño, debe limitar el alcance del trabajo al ViewModel, de modo que después de que se borre el ViewModel, el sistema cancele automáticamente el trabajo para evitar consumir recursos.

class MyViewModel: ViewModel() {
        init {
            viewModelScope.launch {
                // Coroutine that will be canceled when the ViewModel is cleared.
            }
        }
    }

LifecycleScope

LifecycleScope se define para cada objeto de Lifecycle. Las rutinas iniciadas dentro de este rango se cancelarán cuando se destruya el ciclo de vida. Puede acceder a CoroutineScope of Lifecycle a través de la propiedad lifecycle.coroutineScope o lifecycleOwner.lifecycleScope.

El siguiente ejemplo muestra cómo usar lifecycleOwner.lifecycleScope para crear texto precalculado de forma asíncrona:

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)
            }
        }
    }

LifecycleScope + estado del ciclo de vida

Lifecycle proporciona otros métodos: lifecycle.whenCreated, lifecycle.whenStarted y lifecycle.whenResumed. Si Lifecycle no está al menos en el estado mínimo requerido, se suspenderán todas las rutinas que se ejecuten en estos bloques.

El siguiente ejemplo contiene bloques de código que solo se ejecutarán si el ciclo de vida asociado está al menos INICIADO:

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.

            }
        }
    }

Si el Ciclo de vida es destruido por cierto método cuando la corutina está activa, la corutina se cancelará automáticamente. En el siguiente ejemplo, una vez que el estado del ciclo de vida se DESTRUYE, el bloque finalmente se ejecutará:

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.
                    }
                }
            }
        }
    }

Resumen del uso del estado del ciclo de vida de LifecycleScope +
通过一种声明式的写法(即在Activity或者Fragment的初始化时,声明好各个生命周期需要做的事情),而不是程序性的写法(即在各个生命周期回调方法中处理相应逻辑),更有利于整体代码结构的把握,更易于理解和维护。所以建议大家多使用这种具有声明式的写法处理业务逻辑。

Usa corutinas con LiveData

Puede usar la función del generador liveData para llamar a la función de suspensión y transferir el resultado como un objeto LiveData.

En el siguiente ejemplo, loadUser () es una función de pausa declarada en otro lugar. Use la función del generador liveData para llamar a loadUser () de forma asincrónica, luego use emit () para emitir el resultado:

val user: LiveData<User> = liveData {
        val data = database.loadUser() // loadUser is a suspend function.
        emit(data)
    }

Cuando LiveData se activa, el bloque de código comienza a ejecutarse; cuando LiveData se desactiva, el bloque de código se cancela automáticamente después de un tiempo de espera configurable. Si el bloque de código se cancela antes de la finalización, se reiniciará después de que LiveData se vuelva a activar; si se completa con éxito en la ejecución anterior, no se reiniciará. Tenga en cuenta que el bloque de código solo se reiniciará si se cancela automáticamente. Si el bloque de código se cancela por cualquier otro motivo (por ejemplo, se lanza una excepción de cancelación), no se reiniciará.

También puede emitir múltiples valores desde el bloque de código. Cada llamada emit () suspende la ejecución del bloque de código:

val user: LiveData<Result> = liveData {
        emit(Result.loading())
        try {
            emit(Result.success(fetchUser()))
        } catch(ioException: Exception) {
            emit(Result.error(ioException))
        }
    }

También puede usar liveData con transformaciones, como se muestra en el siguiente ejemplo:

class MyViewModel: ViewModel() {
        private val userId: LiveData<String> = MutableLiveData()
        val user = userId.switchMap { id ->
            liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
                emit(database.loadUserById(id))
            }
        }
    }

Puede emitir múltiples valores desde LiveData llamando a la función emitSource () cada vez que desee emitir un nuevo valor. Tenga en cuenta que cada llamada a emit () o emitSource () eliminará la fuente agregada anteriormente.

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)
                    }
                )
            }
        }
    }

Referencia:
Introducción al sitio web oficial de Android:
use las corutinas de Kotlin para mejorar el rendimiento de la aplicación,
use las corutinas de Kotlin con componentes de arquitectura

82 artículos originales publicados · Me gusta 86 · Visita 110,000+

Supongo que te gusta

Origin blog.csdn.net/unicorn97/article/details/104196789
Recomendado
Clasificación