Я создаю приложение, которое получает значения (псевдо) задержки, отправляя запрос на некоторые URL-адреса и записывая, сколько времени это займет.
Во-первых, я использую retrofit для получения ответа JSON от веб-сервера. Этот ответ содержит: имя хоста (например, Ebay UK), URL-адрес хоста (например, www.ebay.co.uk) и URL-адрес изображения. Я сопоставляю этот ответ с моим классом данных, который выглядит следующим образом:
data class(
val name: String,
var url: String,
val icon: String,
var averagePing: Long = -1
)
url-адрес является свойством var, так как перед выполнением вызовов для получения значений задержки мне нужно добавить https://, чтобы сделать запрос.
Я делаю все это вот так:
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) }
}
}
}
Первый цикл for подготавливает мои данные. Строка после цикла for отправляет данные адаптеру recycler, чтобы сразу отобразить имя хоста, URL-адрес и значок (все это работает, т. Е. У меня есть рабочий наблюдатель для LiveData), пока я жду значений задержки.
Второй цикл for вызывает функцию для вычисления значений задержки для каждого хоста, а функция updateHostList() обновляет данные LiveData.
Вот как выглядят функции:
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
}
}
}
Все это происходит в модели представления. В настоящее время я обновляю свой список, отправляя весь список снова, когда я изменяю одно свойство одного элемента списка, что кажется мне ужасным.
Мой вопрос: Как я могу обновить только одно свойство хоста и заставить его автоматически обновлять пользовательский интерфейс?
Заранее спасибо
Редактировать: Мой наблюдатель выглядит так:
viewModel.hostListLiveData.observe(this, Observer { adapter.updateData(it) })
И updateData() выглядит так:
fun updateData(freshHostList: List<Host>) {
hostList.clear()
hostList.addAll(freshHostList)
notifyDataSetChanged()
}
@ArpitShukla, вы предлагаете, чтобы у меня было 2 функции обновления? один для отображения начального списка, а другой для обновления элемента списка? Или я бы просто поместил как notifyDataSetChanged (), так и notifyItemChanged() в updateData()?
Edit2: изменил вызов моей функции, чтобы сделать его асинхронным.