Tengo una clase separada en la que manejo la obtención de datos (específicamente Firebase) y generalmente devuelvo objetos LiveData y los actualizo de forma asincrónica. Ahora quiero tener los datos devueltos almacenados en un ViewModel, pero el problema es que para obtener dicho valor, necesito observar el objeto LiveData devuelto por mi clase de obtención de datos. El método de observación requería un objeto LifecycleOwner como primer parámetro, pero obviamente no lo tengo dentro de mi ViewModel y sé que se supone que no debo mantener una referencia a la Actividad / Fragmento dentro de ViewModel. ¿Qué tengo que hacer?
90
Respuestas:
En esta publicación de blog del desarrollador de Google, José Alcérreca, se recomienda usar una transformación en este caso (ver el párrafo "LiveData en repositorios") porque ViewModel no debería contener ninguna referencia relacionada con
View
(Actividad, Contexto, etc.) porque lo hacía difícil. Probar.fuente
En la documentación de ViewModel
Otra forma es que los datos implementen RxJava en lugar de LiveData, entonces no tendrá el beneficio de ser consciente del ciclo de vida.
En la muestra de Google de todo-mvvm-live-kotlin , usa una devolución de llamada sin LiveData en ViewModel.
Supongo que si desea cumplir con la idea completa de ser un ciclo de vida, debemos mover el código de observación en Actividad / Fragmento. De lo contrario, podemos usar callback o RxJava en ViewModel.
Otro compromiso es implementar MediatorLiveData (o Transformations) y observar (ponga su lógica aquí) en ViewModel. Tenga en cuenta que el observador MediatorLiveData no se activará (igual que Transformaciones) a menos que se observe en Actividad / Fragmento. Lo que hacemos es poner una observación en blanco en Activity / Fragment, donde el trabajo real se realiza en ViewModel.
// ViewModel fun start(id : Long) : LiveData<User>? { val liveData = MediatorLiveData<User>() liveData.addSource(dataSource.getById(id), Observer { if (it != null) { // put your logic here } }) } // Activity/Fragment viewModel.start(id)?.observe(this, Observer { // blank observe here })
PD: leí ViewModels y LiveData: Patterns + AntiPatterns que sugirieron que Transformations. No creo que funcione a menos que se observe LiveData (lo que probablemente requiera que se haga en Activity / Fragment).
fuente
mLiveData.asFlow()
) oobserveForever
.Creo que puede usar observeForever, que no requiere la interfaz del propietario del ciclo de vida y puede observar los resultados del modelo de vista
fuente
Cannot invoke observeForever on a background thread
onCleared
. En cuanto al hilo de fondo, observe desde el hilo principal, eso es todo.observeForever
a ser invocado desde la vía principalGlobalScope.launch(Dispatchers.Main) { myvm.observeForever() }
Utilice corrutinas de Kotlin con componentes de Arquitectura.
Puede utilizar la
liveData
función del constructor para llamar a unasuspend
función, sirviendo el resultado como unLiveData
objeto.val user: LiveData<User> = liveData { val data = database.loadUser() // loadUser is a suspend function. emit(data) }
También puede emitir varios valores desde el bloque. Cada
emit()
llamada suspende la ejecución del bloque hasta que elLiveData
valor se establece en el hilo principal.val user: LiveData<Result> = liveData { emit(Result.loading()) try { emit(Result.success(fetchUser())) } catch(ioException: Exception) { emit(Result.error(ioException)) } }
En su configuración de gradle, use
androidx.lifecycle:lifecycle-livedata-ktx:2.2.0
o superior.También hay un artículo al respecto.
Actualización : también es posible cambiar
LiveData<YourData>
en elDao
interface
. Debe agregar lasuspend
palabra clave a la función:@Query("SELECT * FROM the_table") suspend fun getAll(): List<YourData>
y en el
ViewModel
necesita obtenerlo de forma asincrónica así:viewModelScope.launch(Dispatchers.IO) { allData = dao.getAll() // It's also possible to sync other data here }
fuente