I have a recyclerview which works as expected. I have a button in the layout that fills the list. The button is supposed to make a async call, and on result, I change the button
Chet Haase from Google discusses your exact issue in this DevBytes video.
In short, the framework need to be notified that one of the Views is in "transient" state. Once notified, the framework will not recycle this View until its "transient" flag cleared.
In your case, before you execute the async action, call setHasTransientState(true)
on the child View that should change when the async action completes. This View will not be recycled until you explicitly call setHasTransientState(false)
on it.
Offtopic:
It looks like you might be manipulating UI elements from background threads. Don't do that! If you can have a reference to Activity
then use its runOnUiThread(Runnable action)
API instead. If getting a reference to Activity
is difficult, you can obtain UI thread's Handler
and use its post(Runnable action)
API.
When the async code is done, you should update the data, not the views. After updating the data, tell the adapter that the data changed. The RecyclerView gets note of this and re-renders your view.
When working with recycling views (ListView or RecyclerView), you cannot know what item a view is representing. In your case, that view gets recycled before the async work is done and is assigned to a different item of your data.
So never modify the view. Always modify the data and notify the adapter. bindView should be the place where you treat these cases.
Without code to look at, this is going to be difficult (if not impossible) for people to provide an exact answer. However, based on this description it sounds as though your async network loading (using an AsyncTask
or custom Loader
?) is not specifically tied to an element being tracked by your adapter. You'll need to have some way of tying the two together since the child View
objects shown by the RecyclerView
are re-used to be more efficient. This also means that if a View
is being reused and there is an active async operation tied to it, that async operation will need to be canceled. Otherwise you'll see what you see now: the wrong child View
being updated with content from an older async call.