Bazı url'lere bir istekte bulunarak ve bunun ne kadar süreceğini kaydederek (sözde) gecikme değerlerini alan bir uygulama yapıyorum.
İlk olarak, bir web sunucusundan bir JSON yanıtı almak için güçlendirme kullanıyorum. Bu yanıt şunları içerir: ana bilgisayarın adı (ör. Ebay UK), ana bilgisayarın url'si (ör. www.ebay.co.uk) ve bir resim url'si. Bu yanıtı aşağıdaki gibi görünen veri sınıfımla eşleştiriyorum:
data class(
val name: String,
var url: String,
val icon: String,
var averagePing: Long = -1
)
url bir var özelliğidir, çünkü gecikme değerlerini almak için arama yapmadan önce isteği yapmak için https:// eklemem gerekir.
Sanki bu her şeyi yapıyorum yani:
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) }
}
}
}
İlk for döngüsü verilerimi hazırlar. For döngüsünden sonraki satır, ana bilgisayar adını, url'yi ve simgeyi hemen göstermek için verileri geri dönüştürücü bağdaştırıcısına gönderir (tüm bunlar çalışır, yani LiveData için çalışan bir gözlemcim var), gecikme değerlerini beklerken.
İkinci for döngüsü, her ana bilgisayar için gecikme değerlerini hesaplama işlevini çağırır ve updateHostList () işlevi livedata'yı günceller.
İşlevler böyle görünür:
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
}
}
}
Bütün bunlar Viewmodel'de gerçekleşir. Şu anda listenin bir öğesinin bir özelliğini değiştirdiğimde tüm listeyi tekrar göndererek listemi güncelliyorum, ki bu bana korkunç geliyor.
Benim sorum Nasıl ev sahibi tek özelliği güncelleme ve otomatik olarak UI yenilemek zorunda miyim?
Şimdiden teşekkür ederiz
Düzenleme: Gözlemcim şuna benziyor:
viewModel.hostListLiveData.observe(this, Observer { adapter.updateData(it) })
Ve updateData() şöyle görünür:
fun updateData(freshHostList: List<Host>) {
hostList.clear()
hostList.addAll(freshHostList)
notifyDataSetChanged()
}
@ArpitShukla, 2 güncelleme işlevine sahip olmamı öneriyor musunuz? biri ilk listeyi göstermek için diğeri de listenin öğesini güncellemek için mi? Yoksa hem notifyDataSetChanged() hem de notifyItemChanged() öğesini updateData () öğesine koyar mıyım?
Edıt2: işlev çağrımı zaman uyumsuz hale getirmek için değiştirdi.