Sto facendo un'app che ottiene la (pseudo) latenza valori mediante richiesta di alcuni url e la registrazione del tempo che vorrà.
Primo, io uso retrofit per ottenere una risposta JSON da un server web. Questa risposta contiene: il nome dell'host (ad esempio Ebay UK), l'url dell'host (ad es. www.ebay.co.uk), e l'url di un'immagine. Ho una mappa di questa risposta sulla mia classe di dati che è simile alla seguente:
data class(
val name: String,
var url: String,
val icon: String,
var averagePing: Long = -1
)
url è una var di proprietà come prima di effettuare le chiamate per ottenere i valori di latenza, ho bisogno di aggiungere https:// per fare la richiesta.
Sto facendo tutto questo, in questo modo:
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) }
}
}
}
Il primo ciclo for prepara i miei dati. La linea dopo il ciclo for, invia i dati al centro di riciclaggio adattatore, per mostrare il nome host e l'url e l'icona subito (tutto questo funziona, cioè io ho un lavoro di osservatore per il LiveData), mentre sono in attesa per la latenza valori.
Il secondo ciclo for chiama la funzione per calcolare i valori di latenza per ogni host e il updateHostList() la funzione aggiorna il LiveData.
Questo è come le funzioni look:
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
}
}
}
Tutto questo accade nel viewModel. Attualmente sto aggiornando la mia lista inviando l'intero elenco di nuovo quando si modifica una proprietà di un elemento della lista, che sembra orribile per me.
La mia domanda è: Come posso aggiornare solo la proprietà di host e farlo aggiornare l'interfaccia utente, automaticamente?
Grazie in anticipo
Edit: il Mio osservatore assomiglia a questo:
viewModel.hostListLiveData.observe(this, Observer { adapter.updateData(it) })
E updateData() assomiglia a questo:
fun updateData(freshHostList: List<Host>) {
hostList.clear()
hostList.addAll(freshHostList)
notifyDataSetChanged()
}
@ArpitShukla, ti suggeriscono avrei 2 funzioni di aggiornamento? uno per mostrare la lista iniziale e un altro per aggiornare voce di elenco? O dovrei solo mettere entrambi notifyDataSetChanged() e notifyItemChanged() in updateData()?
Edit2: ha cambiato la mia chiamata di funzione per rendere asincrono.