30

我正在将我的适配器移植到RecyclerView.Adapter

我想要实现的目标: 当用户在接近尾声时向下滚动时,我想开始获取数据,我还想在最后添加我的 ProgressBar 视图,让用户知道更多数据即将到来。

我在 BaseAdapter 中实现这一点的方式:getView接近结尾处请求的视图中,我将开始获取更多数据,调用 notifyDataSetChanged(以显示 ProgressBar 视图),然后才返回所需的视图getView

我在 RecyclerView.Adapter 中尝试做的事情:我基本上尝试做同样的事情,这次是在方法onBindViewHolder中,

但是如果我尝试notifyItemInserted在这个方法中调用,我会得到以下异常:

IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling

我尝试了什么:我注意到它onBindViewHolder是从onLayoutChildrenfrom调用的LayoutManager,我尝试覆盖它并notifyItemInserted在它之后调用,super但我得到了同样的异常

我怎样才能实现我的目标?

4

6 回答 6

46
        Handler handler = new Handler();

        final Runnable r = new Runnable() {
            public void run() {
                adapter.notifyDataSetChanged();
            }
        };

        handler.post(r);

我调用 adapter.notifyDataSetChanged(); 的示例代码 从活动

于 2015-09-18T05:28:48.407 回答
22

还值得注意的RecyclerView.isComputingLayout()是触发此异常的方法上的 JavaDoc:

/**
 * Returns whether RecyclerView is currently computing a layout.
 * <p>
 * If this method returns true, it means that RecyclerView is in a lockdown state and any
 * attempt to update adapter contents will result in an exception because adapter contents
 * cannot be changed while RecyclerView is trying to compute the layout.
 * <p>
 * It is very unlikely that your code will be running during this state as it is
 * called by the framework when a layout traversal happens or RecyclerView starts to scroll
 * in response to system events (touch, accessibility etc).
 * <p>
 * This case may happen if you have some custom logic to change adapter contents in
 * response to a View callback (e.g. focus change callback) which might be triggered during a
 * layout calculation. In these cases, you should just postpone the change using a Handler or a
 * similar mechanism.
 *
 * @return <code>true</code> if RecyclerView is currently computing a layout, <code>false</code>
 *         otherwise
 */
public boolean isComputingLayout() {
    return mLayoutOrScrollCounter > 0;
}

突出的短语是:

在这些情况下,您应该使用 Handler 或类似机制来推迟更改。

就我而言,我正在从另一个线程修改适配器内容,这(偶尔)会导致冲突。将更新转移到 UI 线程上的处理程序自然可以解决这个问题。

于 2015-11-26T21:11:11.780 回答
9

Using a Handler for adding items and calling notify...() from this Handler fixed the issue for me.

于 2015-01-26T16:13:42.710 回答
6

简洁明了方法

  recyclerView.post(new Runnable() {
                    @Override
                    public void run() {
                        adapter.notifyDataSetChanged();
                    }
                });

说明:您使用您的RecyclerView实例并在 post 方法中将新Runnable添加到消息队列中。runnable 将在用户界面线程上运行。这是 Android 从后台访问 UI 线程的限制(例如,在将在后台线程中运行的方法内)。

于 2017-04-22T12:42:28.520 回答
1

尝试这个

if (!recyclerView.isComputingLayout()) {
        recyclerView.notifyDataSetChanged();
    }
于 2017-06-01T12:29:28.210 回答
0

我用这个:

Handler handler = new Handler();
private void notifyItemInsertedEx(final int position) {
    try {
        notifyItemInserted(position);
    } catch (Exception ex) {
        handler.post(new Runnable(){
            public void run(){
                notifyItemInserted(position);
            }
        });
    }
}
于 2017-08-22T09:53:51.400 回答