Tenho uma classe separada em que lido com a busca de dados (especificamente Firebase) e normalmente retorno objetos LiveData a partir dela e os atualizo de forma assíncrona. Agora quero ter os dados retornados armazenados em um ViewModel, mas o problema é que, para obter esse valor, preciso observar o objeto LiveData retornado da minha classe de busca de dados. O método observar exigia um objeto LifecycleOwner como o primeiro parâmetro, mas obviamente não tenho isso dentro do meu ViewModel e sei que não devo manter uma referência à Activity / Fragment dentro do ViewModel. O que devo fazer?
95
Respostas:
Em este blog pelo Google desenvolvedor Jose alcerreca é recomendado o uso de uma transformação neste caso (ver o "LiveData em repositórios" parágrafo) porque ViewModel não deverá manter qualquer referência relacionada com
View
(Activity, Contexto etc), porque ele tornava difícil testar.fonte
Na documentação do ViewModel
Outra maneira é os dados implementarem RxJava em vez de LiveData, então não terão o benefício de serem cientes do ciclo de vida.
Na amostra do google de todo-mvvm-live-kotlin , ele usa um retorno de chamada sem LiveData em ViewModel.
Eu estou supondo que se você deseja cumprir com a ideia de ser um software de ciclo de vida, precisamos mover o código de observação em Activity / Fragment. Caso contrário, podemos usar callback ou RxJava em ViewModel.
Outro compromisso é implementar MediatorLiveData (ou Transformations) e observar (colocar sua lógica aqui) em ViewModel. Observe que o observador MediatorLiveData não disparará (o mesmo que Transformations), a menos que seja observado em Activity / Fragment. O que fazemos é colocar um vazio observe em Activity / Fragment, onde o trabalho real é realmente feito em 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 })
PS: Eu li ViewModels e LiveData: Patterns + AntiPatterns que sugeriam Transformations. Não acho que funcione a menos que o LiveData seja observado (o que provavelmente requer que seja feito em Activity / Fragment).
fonte
mLiveData.asFlow()
) ouobserveForever
.Eu acho que você pode usar o observeForever, que não requer a interface do proprietário do ciclo de vida, e você pode observar os resultados do modelo de visualização
fonte
Cannot invoke observeForever on a background thread
onCleared
. Quanto ao tópico de fundo - observe do tópico principal, é isso.observeForever
a invocação do main viaGlobalScope.launch(Dispatchers.Main) { myvm.observeForever() }
Use corrotinas Kotlin com componentes de arquitetura.
Você pode usar a
liveData
função de construtor para chamar umasuspend
função, servindo o resultado como umLiveData
objeto.val user: LiveData<User> = liveData { val data = database.loadUser() // loadUser is a suspend function. emit(data) }
Você também pode emitir vários valores do bloco. Cada
emit()
chamada suspende a execução do bloco até que oLiveData
valor seja definido na thread principal.val user: LiveData<Result> = liveData { emit(Result.loading()) try { emit(Result.success(fetchUser())) } catch(ioException: Exception) { emit(Result.error(ioException)) } }
Na configuração do Gradle, use
androidx.lifecycle:lifecycle-livedata-ktx:2.2.0
ou superior.Também existe um artigo sobre isso.
Atualização : Também é possível alterar
LiveData<YourData>
noDao
interface
. Você precisa adicionar asuspend
palavra-chave à função:@Query("SELECT * FROM the_table") suspend fun getAll(): List<YourData>
e no
ViewModel
você precisa obtê-lo de forma assíncrona assim:viewModelScope.launch(Dispatchers.IO) { allData = dao.getAll() // It's also possible to sync other data here }
fonte