Eu estou fazendo uma aplicação que fica o (pseudo) valores de latência através de um pedido a alguns urls e gravação de quanto tempo isso vai levar.
Primeiro, eu uso o retrofit, para obter uma resposta JSON a partir de um servidor web. Esta resposta se contém: o nome do host (por exemplo, o Ebay UK), a url do host (por exemplo, www.ebay.co.uk), e a url de uma imagem. Eu mapa esta resposta para a minha classe de dados que se parece com o seguinte:
data class(
val name: String,
var url: String,
val icon: String,
var averagePing: Long = -1
)
o url é um var de propriedade como antes de fazer as chamadas para obter os valores de latência, eu preciso adicionar https:// para fazer a solicitação.
Eu estou fazendo tudo isso assim:
fun getHostsLiveData() {
viewModelScope.launch(Dispatchers.IO) {
val hostList = repo.getHosts()
for (host in hostList) {
host.url = "https://" + host.url
host.averagePing = -1
}
hostListLiveData.postValue(hostList)//updated the recyclerview with initial values
//with default (-1) value of averagePing
for (host in hostList) {
async { pingHostAndUpdate(host.url, hostList) }
}
}
}
O primeiro loop for prepara os meus dados. A linha após o loop for submete os dados para o reciclador adaptador, a fim de mostrar o nome do host, a url e o ícone de imediato (isso tudo funciona por exemplo, eu tenho um trabalho de observador para o LiveData), enquanto eu estou esperando o valores de latência.
O segundo loop chama a função para calcular os valores de latência para cada host e o updateHostList() função atualiza a LiveData.
Esta é a forma como as funções olhada:
suspend fun pingHostAndUpdate(url: String, hostList: MutableList<Host>) {
try {
val before = Calendar.getInstance().timeInMillis
val connection = URL(url).openConnection() as HttpURLConnection //Need error handling
connection.connectTimeout = 5*1000
connection.connect()
val after = Calendar.getInstance().timeInMillis
connection.disconnect()
val diff = after - before
updateHostList(url, diff, hostList)
} catch (e: MalformedURLException) {
Log.e("MalformedURLExceptionTAG", "MalformedURLException")
} catch (e: IOException) {
Log.e("IOExceptionTAG", "IOException")
}
}
fun updateHostList(url: String, pingResult: Long, hostList: MutableList<Host>) {
//All this on mainThread
var foundHost: Host? = null
var index = 0
for (host in hostListLiveData.value!!) {
if (host.url == url) {
foundHost = host
break
}
index++
}
if (foundHost != null) {
viewModelScope.launch(Dispatchers.Main) {
val host = Host(foundHost.name, foundHost.url, foundHost.icon, pingResult)
Log.d("TAAAG", "$host")
hostList[index] = host
hostListLiveData.value = hostList
}
}
}
Tudo isso acontece em viewModel. Atualmente estou atualizando minha lista de submeter toda a lista novamente, quando eu alterar uma propriedade de um elemento da lista, que parece horrível para mim.
A minha pergunta é: Como posso actualizar apenas uma propriedade do host e ter que atualizar a INTERFACE do usuário automaticamente?
Obrigado antecipadamente
Edit: o Meu observador parecido com este:
viewModel.hostListLiveData.observe(this, Observer { adapter.updateData(it) })
E updateData() se parece com isso:
fun updateData(freshHostList: List<Host>) {
hostList.clear()
hostList.addAll(freshHostList)
notifyDataSetChanged()
}
@ArpitShukla, você sugere que eu gostaria de ter 2 funções de atualização? um para mostrar a lista inicial e outro para a atualização no item da lista? Ou será que eu apenas colocar notifyDataSetChanged() e notifyItemChanged() em updateData()?
Edit2: mudou a minha chamada de função para torná-lo assíncrona.