I'm trying to call recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,null,0)
only after mDiffer.submitlist(list)
is finished "diffing" and animating the list updates/changes.
Is there an AsyncListDiffer feature for onAfterSubmitList(Callback callback)
that I could use to achieve this?
If not, is there anyway to find out when does submitList()
finish its task so I could put my scrollToPosition(0)
in there?
Update July 2020:
Google added a callback for this! See: https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer#submitList(java.util.List%3CT%3E,%20java.lang.Runnable)
Previous answer, from the bad old days:
First of all, I can't believe Google didn't provide a callback for this.
I dived into the source code of
AsyncListDiffer
, and I found that it's possible to receive a callback when all RecyclerView updates have been done - but the way to receive this callback is just bizarre.You need to create a sub-class of
BatchingListUpdateCallback
, and then wrap yourListUpdateCallback
(orAdapterListUpdateCallback
as in most cases) inside it.Then, you should override
dispatchLastEvent
.AsyncListDiffer
will call this after all but one of the updates have been dispatched. In yourdispatchLastEvent
, you'll want to call the super implementation, so you don't break anything. You'll also want to invoke a custom callback, which is your way in.In Kotlin that looks like:
The last step is to then provide your custom
OnDiffDoneListUpdateCallback
to theAsyncListDiffer
. To do this, you need to initialise theAsyncListDiffer
for yourself - if you're usingListAdapter
or something similar, you'll need to refactor so that you are in control of theAsyncListDiffer
.In Kotlin, that looks like:
Edit: I forgot about the edge-cases, of course!
Sometimes,
dispatchLastEvent
isn't called, becauseAsyncListDiffer
considers the update trivial. Here's the checks it does:I recommend doing these checks for yourself, just before you call
asyncListDiffer.submitList(list)
. But of course, it couldn't be that easy!mList
is private, andgetCurrentList
will return an empty list ifmList
is null, so is useless for this check. Instead you'll have to use reflection to access it:Edit 2: Now, I know what you're saying - surely there's an easier, less hacky way to do this? And the answer is... yes! Simply copy the entire
AsyncListDiffer
class into your project, and just add the callback yourself!