5
votes

I use SortedList in RecyclerView Adapter and I'd like to know when RecyclerView has finished its update after I change data in Adapter (and called proper method e.g. notifyItemRangeChanged). Is there any way to do this?

My problem is that I need to scroll RecyclerView to the top after filtering its content. I call from Activity method on my Adapter which filter items on its member. After that I just call scrollToPosition(0) on RecyclerView and its not always work as expected, especially when after changes operation on list is only 1 item.

Here is code of update method I call on my adapter:

private SortedList<Game> games;
private ArrayList<Game> allGames;

public void search(String query) {
    replaceAll(filterGames(query));
}

public void replaceAll(Collection<Game> games) {
    this.games.beginBatchedUpdates();
    List<Game> gamesToRemove = new ArrayList<>();
    for (int i = 0; i < this.games.size(); i++) {
        Game game = this.games.get(i);
        if (!games.contains(game)) {
            gamesToRemove.add(game);
        }
    }
    for (Game game : gamesToRemove) {
        this.games.remove(game);
    }
    this.games.addAll(games);
    this.games.endBatchedUpdates();
}

private Collection<Game> filterGames(String query) {
    query = query.toLowerCase();
    List<Game> filteredGames = new ArrayList<>();
    for (Game game : allGames) {
        String gameTitle = game.getTitle().toLowerCase();
        if (gameTitle.contains(query)) {
            filteredGames.add(game);
        }
    }
    return filteredGames;
}

And here how I call it from Activity:

private RecyclerView gamesList;
private GameAdapter gamesAdapter;

@Override
public boolean onQueryTextChange(String newText) {
    gamesAdapter.search(newText);
    gamesList.scrollToPosition(0);
    return false;
}
4
But what do you need that for? What is the use-case?azizbekian
I want to scroll RecyclerView to the top after add/remove items. When I try to scroll just after I start update on adapter there are problems because items are still being processed.ostojan
because items are still being processed how can they "be processed" if they are out of the screen, thus they are detached from window?azizbekian
They are moving from old to new positions. I'm talking about animations. When I've added delay between call for update and scroll to first position there was no problem.ostojan
I think you are missing something. Most possibly you won't ever need to know when "update" has finished. If you wait until "update" finishes (which means that e.g. 7 times onBindViewHolder was called, because that much items are active currently), then how would it affect the item that is off the screen? You still will be performing that "processing" as soon as onBindViewHolder() would be called for that item.azizbekian

4 Answers

0
votes

Try using,

recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    //At this point the layout is complete and the 
                    //dimensions of recyclerView and any child views are known.
                }
            });
0
votes

you can use RecyclerAdapter.registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer)

For listening to changed views:

extends LayoutManager then override onItemUpdated(RecyclerView recyclerView, int positionStart, int itemCount, Object payload)
0
votes

You can use recyclerView.itemAnimator?.isRunning for this purpose.

0
votes

Your issue seams related to this.

I tried this and it worked for me. Here is the Kotlin extension

fun RecyclerView.runWhenReady(action: () -> Unit) {
    val globalLayoutListener = object: ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            action()
            viewTreeObserver.removeOnGlobalLayoutListener(this)
        }
    }
    viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
}

then call it

myRecyclerView.runWhenReady {
    // Your action
}