I have a sorted list I would like to use to hold objects for maintaining a recycleview as usual.
The api I am interfacing with passes me updates through an interface callback using multiple threads. This api can add, remove or update object state. When the app opens there is a flurry of adds, removes and updates. Then it slowes down to some degreee. This is a reverse of the typical database paradigm where the UI updates faster than the data to one where the data updates faster than the UI
This seems to be an issue with the sortedList in android for several reasons.
adding an item to sortedlist must be done on UI thread if updates to list are going to fully execute without simply adding to the list and swallowing the error in a background thread when trying to show the update
to change an object state you must first get the index. then get the item. if your multithreading then you get index errors due to race conditions and pull the wrong object
you can affect a list item object’s state in a background thread but this still relies on a call to recalculate() or updateitem() type calls. this leads to reycleview is computing layout errors
Question: Which design pattern would you use to solve this issue? Below are some of my ideas
solutions that seem bad
Swallow errors and use a timer to call notifydatasetchanged(). This really eliminates the purpose of using the sorted list.
Collect updates in another list and do batch updates when size() > someNumber or some timer. why bother using sortedlist
solution that seems good
add all object into a concurrent hashmap. This solves the threading and update issues. But I still need to present a sorted list to the UI. This means batching add and remove for the sorted list. Then also calling notifydatasetChanged() from time to time to handle object state updates
My fantasy solution that maybe exists already is to use an object that holds a concurrent sorted list where I can add, remove and update from a background thread and also bind to a recycleview adpater.
Advertisement
Answer
My solution is to hold updates in a buffer which can only fire after a time delay. Then putting the update objects into both a concurrent hashmap for easy object retrieval as well as a sortedlist for easy ui display
The api calls this method. I have another version that can run off the ui thread by simply detaching the adapter in sortedlist callbacks.
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; } }); } }
The performbatch() handles a single update. If the object is new it puts it into a concurrent hashmap with its id as a key. Then adds it to the sortedlist. When an update occurs I pull the object from the hashmap, do the update and add it to the sortedlist. The sortedlist api then replaces the old object and updates the sort order.
edit:this does have a slight drag according to androids skipped frames warning. You can detach the adapter from the sortedlist and do updates on a worker thread but I’m not sure if that has any value as this is working alright for now.