Android 回收视图更新排序列表并发问题
Android recycle view update sort list with concurrency issue
我有一个排序列表,我想用来保存对象以像往常一样维护回收视图。
我正在与之交互的 api 使用多线程通过接口回调向我传递更新。 api 可以添加、删除或更新对象状态。当应用程序打开时,会有一连串的添加、删除和更新。然后它会减慢到某种程度。这与典型的数据库范例相反,其中 UI 比数据更新更快,而数据更新比 UI
更快
这似乎是 android 中 sortedList 的一个问题,原因有几个。
如果要完全执行对列表的更新而不是简单地添加到列表并在尝试时吞没后台线程中的错误,则必须在 UI 线程上将项目添加到排序列表显示更新
要更改对象状态,您必须先获取索引。然后得到该项目。如果你的多线程那么你会因为竞争条件而得到索引错误并拉出错误的对象
您可以在后台线程中影响列表项对象的状态,但这仍然依赖于对 recalculate() 或 updateitem() 类型调用的调用。这导致 reycleview 正在计算布局错误
问题:您会使用哪种设计模式来解决这个问题?以下是我的一些想法
看起来很糟糕的解决方案
吞下错误并使用计时器调用 notifydatasetchanged()。这确实消除了使用排序列表的目的。
在另一个列表中收集更新,并在 size() > someNumber 或某个计时器时进行批量更新。为什么要费心使用 sortedlist
看起来不错的解决方案
将所有对象添加到并发哈希图中。这解决了线程和更新问题。但我仍然需要向 UI 呈现一个排序列表。这意味着对排序列表进行批处理添加和删除。然后还时不时调用notifydatasetChanged()来处理对象状态更新
我可能已经存在的幻想解决方案是使用一个包含并发排序列表的对象,我可以在其中添加、删除和更新后台线程,还可以绑定到 recycleview adpater。
我的解决方案是将更新保存在缓冲区中,该缓冲区只能在一段时间延迟后触发。然后将更新对象放入一个并发哈希图中以便于对象检索以及一个排序列表以便于 ui 显示
api调用这个方法。我有另一个版本可以通过简单地在排序列表回调中分离适配器来 运行 关闭 ui 线程。
public void onResult(Object object) {
if ( !currentlyProcessing && System.currentTimeMillis() > (lastBatch + delay)) {
currentlyProcessing = true;
runOnUiThread(new Runnable() {
@Override
public void run() {
easyChatList.beginBatchedUpdates();
while (batchBuilder.size() > 0){
performBatch(batchBuilder.remove(0));
}
easyChatList.endBatchedUpdates();
lastBatch = System.currentTimeMillis();
currentlyProcessing = false;
}
});
}
}
performbatch() 处理单个更新。如果对象是新的,它会将其放入并发哈希图中,并以其 id 作为键。然后将其添加到排序列表中。当发生更新时,我从哈希图中拉出对象,进行更新并将其添加到排序列表中。排序列表 api 然后替换旧对象并更新排序顺序。
编辑:根据 android 跳帧警告,这确实有轻微的阻力。您可以从排序列表中分离适配器并在工作线程上进行更新,但我不确定它是否有任何价值,因为它现在工作正常。
我有一个排序列表,我想用来保存对象以像往常一样维护回收视图。
我正在与之交互的 api 使用多线程通过接口回调向我传递更新。 api 可以添加、删除或更新对象状态。当应用程序打开时,会有一连串的添加、删除和更新。然后它会减慢到某种程度。这与典型的数据库范例相反,其中 UI 比数据更新更快,而数据更新比 UI
更快这似乎是 android 中 sortedList 的一个问题,原因有几个。
如果要完全执行对列表的更新而不是简单地添加到列表并在尝试时吞没后台线程中的错误,则必须在 UI 线程上将项目添加到排序列表显示更新
要更改对象状态,您必须先获取索引。然后得到该项目。如果你的多线程那么你会因为竞争条件而得到索引错误并拉出错误的对象
您可以在后台线程中影响列表项对象的状态,但这仍然依赖于对 recalculate() 或 updateitem() 类型调用的调用。这导致 reycleview 正在计算布局错误
问题:您会使用哪种设计模式来解决这个问题?以下是我的一些想法
看起来很糟糕的解决方案
吞下错误并使用计时器调用 notifydatasetchanged()。这确实消除了使用排序列表的目的。
在另一个列表中收集更新,并在 size() > someNumber 或某个计时器时进行批量更新。为什么要费心使用 sortedlist
看起来不错的解决方案
将所有对象添加到并发哈希图中。这解决了线程和更新问题。但我仍然需要向 UI 呈现一个排序列表。这意味着对排序列表进行批处理添加和删除。然后还时不时调用notifydatasetChanged()来处理对象状态更新
我可能已经存在的幻想解决方案是使用一个包含并发排序列表的对象,我可以在其中添加、删除和更新后台线程,还可以绑定到 recycleview adpater。
我的解决方案是将更新保存在缓冲区中,该缓冲区只能在一段时间延迟后触发。然后将更新对象放入一个并发哈希图中以便于对象检索以及一个排序列表以便于 ui 显示
api调用这个方法。我有另一个版本可以通过简单地在排序列表回调中分离适配器来 运行 关闭 ui 线程。
public void onResult(Object object) {
if ( !currentlyProcessing && System.currentTimeMillis() > (lastBatch + delay)) {
currentlyProcessing = true;
runOnUiThread(new Runnable() {
@Override
public void run() {
easyChatList.beginBatchedUpdates();
while (batchBuilder.size() > 0){
performBatch(batchBuilder.remove(0));
}
easyChatList.endBatchedUpdates();
lastBatch = System.currentTimeMillis();
currentlyProcessing = false;
}
});
}
}
performbatch() 处理单个更新。如果对象是新的,它会将其放入并发哈希图中,并以其 id 作为键。然后将其添加到排序列表中。当发生更新时,我从哈希图中拉出对象,进行更新并将其添加到排序列表中。排序列表 api 然后替换旧对象并更新排序顺序。
编辑:根据 android 跳帧警告,这确实有轻微的阻力。您可以从排序列表中分离适配器并在工作线程上进行更新,但我不确定它是否有任何价值,因为它现在工作正常。