【问题标题】:How to find out that RecyclerView has finished update?如何发现 RecyclerView 已经完成更新?
【发布时间】:2017-04-12 19:03:05
【问题描述】:

我在 RecyclerView Adapter 中使用 SortedList,我想知道在我更改 Adapter 中的数据后 RecyclerView 何时完成更新(并调用了适当的方法,例如 notifyItemRangeChanged)。有没有办法做到这一点?

我的问题是我需要在过滤其内容后将 RecyclerView 滚动到顶部。我从适配器上的 Activity 方法调用,该方法过滤其成员上的项目。之后我只是在 RecyclerView 上调用 scrollToPosition(0) ,它并不总是按预期工作,尤其是当列表上的更改后操作只有 1 项时。

这是我在适配器上调用的更新方法的代码:

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;
}

这里我如何从 Activity 中调用它:

private RecyclerView gamesList;
private GameAdapter gamesAdapter;

@Override
public boolean onQueryTextChange(String newText) {
    gamesAdapter.search(newText);
    gamesList.scrollToPosition(0);
    return false;
}

【问题讨论】:

  • 但是你需要它做什么?用例是什么?
  • 我想在添加/删除项目后将 RecyclerView 滚动到顶部。当我在适配器上开始更新后尝试滚动时,会出现问题,因为项目仍在处理中。
  • because items are still being processed 如果它们不在屏幕上,如何“被处理”,从而与窗口分离?
  • 他们正在从旧职位转移到新职位。我说的是动画。当我在更新调用和滚动到第一个位置之间添加延迟时,没有问题。
  • 我认为你遗漏了一些东西。很可能您永远不需要知道“更新”何时完成。如果您等到“更新”完成(这意味着例如调用了 7 次 onBindViewHolder,因为当前有很多项目处于活动状态),那么它将如何影响屏幕外的项目?只要为该项目调用onBindViewHolder(),您仍将执行该“处理”。

标签: android android-recyclerview


【解决方案1】:

尝试使用,

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.
                }
            });

【讨论】:

  • 这仍然不是我想要的。此方法看起来像在每个应用程序框架中调用。即使我设置了我已经编辑数据的标志,然后才执行我的操作,RecyclerView 中的更改仍在进行中。
【解决方案2】:

你可以使用RecyclerAdapter.registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer)

用于收听更改的视图:

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

【讨论】:

  • 我已经厌倦了这个,但这样我只能发现请求更新,而不是已经完成。
  • 看来你需要使用 LayoutManager.onItemUpdated
  • 这几乎就是我想要的。如果我从列表中删除项目,它会正常工作。当我在实际第一个项目之前添加项目并在 onItemUpdated 中调用 scrollToPosition(0) 时,它不起作用。
  • 使用 postDelayed() 进行滚动
  • 我知道 postDelayed 有效,但我正在寻找“更清洁”的解决方案。
【解决方案3】:

您可以为此使用recyclerView.itemAnimator?.isRunning

【讨论】:

    【解决方案4】:

    您的问题与this 相关。

    我试过这个,它对我有用。这是 Kotlin 扩展

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

    然后调用它

    myRecyclerView.runWhenReady {
        // Your action
    }
    

    【讨论】:

      猜你喜欢
      • 2010-11-05
      • 2018-12-26
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 2020-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多