Quando faço download de informações de um banco de dados, a função de coleta não interrompe a emissão (a função de coleta do Kotlin não termina sozinha).
Eu tenho esta classe de entidade:
@Entity
data class ShareEntity(
@PrimaryKey(autoGenerate = false)
val secId: String,
val shortName: String,
val fullName: String = "",
val isFavorite: Boolean
)
A função para obter todos os compartilhamentos específicos de “isFavorite” no Dao é assim:
@Dao
interface DataBaseDao {
………..
@Query("SELECT * FROM ShareEntity WHERE isFavorite =:isFavorite")
fun getAllSharesByIsFavorite(isFavorite: Boolean): Flow<List<ShareEntity>>
}
No DataBaseDao existem muitas outras funções que inserem alguns dados na entidade ShareEntity.
Para trabalhar com a interface Dao foi feito o DataBaseRepository e sua implementação DataBaseRepositoryIm:
interface DataBaseRepository {
………..
fun getAllSharesByIsFavorite(isFavorite: Boolean): Flow<List<ShareEntity>>
}
class DataBaseRepositoryIm(
private val dataBaseDao: DataBaseDao
) : DataBaseRepository{
………..
override fun getAllSharesByIsFavorite(isFavorite: Boolean): Flow<List<ShareEntity>> {
return dataBaseDao.getAllSharesByIsFavorite(isFavorite)
}
}
No meu NewsScreenViewModel1 tenho uma função que carrega todos os compartilhamentos por “isFavorite”
@HiltViewModel
class NewsScreenViewModel1 @Inject constructor(
private val dataBaseRepository: DataBaseRepository,
private val repository: ApiRepository,
) : ViewModel(){
suspend fun downloadListOfSharesByIsFavorite(isFavorite: Boolean = true){
val shares = dataBaseRepository.getAllSharesByIsFavorite(isFavorite).collect{ it:List<ShareEntity> ->
println("NewsScreenVM1: allShares is with isFavorite = $isFavorite are $it")
println("NewsScreenVM1: the size of shares is ${it.size}")
}
println("NewsScreenVM1: Now we are outside of the collect function")
}
}
No NewsScreen combinável eu inicio a função com LauncheEffect:
@Composable
fun NewsScreen(
NewsScreenViewModel1: NewsScreenViewModel1 = hiltViewModel()
) {
LaunchedEffect(key1 = Unit) {
NewsScreenViewModel1.downloadListOfSharesByIsFavorite()
}
}
O problema é que a função collect não termina sozinha ou, em outras palavras, não para. No LogCat vejo:
“NewsScreenVM1: allShares está com isFavorite = true são [ShareEntity(secId=ALRS, shortName=АЛРОСА ао, fullName=, isFavorite=true), ShareEntity(secId=AGRO, shortName=AGRO-гдр, fullName=, isFavorite=true), ShareEntity(secId=AFLT, shortName=Аэрофлот, fullName=, isFavorite=true), ShareEntity(secId=FEES, shortName=Россети, fullName=, isFavorite=true)]”
“NewsScreenVM1: o tamanho dos compartilhamentos é 4”
E não há: “NewsScreenVM1: Agora estamos fora da função de coleta”, o que significa que a função de coleta não interrompeu sua emissão e ainda está em execução.
O que eu fiz errado? Por que não consigo executar linhas do código depois de coletar alguns dados do banco de dados?
Tentei executar o fluxo em um escopo de corrotina diferente como este:
fun downloadListOfSharesByIsFavorite(isFavorite: Boolean = true){
viewModelScope.launch {
val shares = dataBaseRepository.getAllSharesByIsFavorite(isFavorite).collect{ it:List<ShareEntity> ->
println("NewsScreenVM1: allShares is with isFavorite = $isFavorite are $it")
println("NewsScreenVM1: the size of shares is ${it.size}")
}
println("NewsScreenVM1: Now we are outside of the collect function")
}
}
Mas a mensagem 'NewsScreenVM1: Agora estamos fora da função de coleta' aparece logo antes de todos os cálculos, o que não é o que eu quero. Quero que seja a última massagem.
Quando uso a função assíncrona com .await() também não recebo a última mensagem, pois o fluxo nunca para. Aqui está o código:
suspend fun downloadListOfSharesByIsFavorite(isFavorite: Boolean = true) {
val asyncValue = viewModelScope.async {
var size = 0
val shares = dataBaseRepository.getAllSharesByIsFavorite(isFavorite)
.collect { it: List<ShareEntity> ->
println("NewsScreenVM1: allShares is with isFavorite = $isFavorite are $it")
println("NewsScreenVM1: the size of shares is ${it.size}")
size = it.size
}
size
}
println("NewsScreenVM1: Now we are outside of the collect function. The list size is ${asyncValue.await()}")
}
Esse é o objetivo de usar um arquivo
Flow
. Não termina porque está aguardando atualizações do banco de dados. Cada vez que a lista for alterada no banco de dados, você obterá a nova lista atualizada no formatocollect
. Por design, não foi feito para acabar: https://developer.android.com/codelabs/basic-android-kotlin-training-intro-room-flowSe o que você deseja é apenas consultar a lista atual uma vez, não há necessidade de
Flow
nemcollect
chamada. Basta usar umasuspend
função que retorne umList
.