【发布时间】:2022-01-02 09:56:30
【问题描述】:
我正在制作一个应用程序,它通过向某些 url 发出请求并记录需要多长时间来获取(伪)延迟值。
首先,我使用改造从 Web 服务器获取 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 循环之后的行将数据提交给回收器适配器,以便立即显示主机名、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 中。目前,当我更改列表的一个元素的一个属性时,我正在通过再次提交整个列表来更新我的列表,这对我来说似乎很可怕。
我的问题是:如何只更新主机的一个属性并让它自动刷新 UI?
提前致谢
编辑:我的观察者看起来像这样:
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:更改了我的函数调用以使其异步。
【问题讨论】:
-
您最关心的是哪一部分?多次将新列表传递给回收站视图可能会影响性能? (顺便说一句,您的
pingHost2函数没有并行运行。您使用一台主机调用它,然后立即等待响应)。 -
@ArpitShukla 传递一个新列表会导致回收器视图重新下载图像,这看起来有问题。我知道 ping 功能不好,我是 Kotlin 的新手,我现在的首要任务是了解 LiveData。