RecyclerView notifyItemInserted IllegalStateException

时间:2014-10-24 20:04:43

标签: android android-5.0-lollipop android-recyclerview

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

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

我在我的BaseAdapter中实现这个的方式:getView附近请求的视图中,我将开始获取更多数据,调用notifyDataSetChanged(以获取ProgressBar视图show)然后才返回getView所需的视图。

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

但如果我尝试在此方法中调用notifyItemInserted,则会出现以下异常:

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

我尝试了什么:我注意到onBindViewHolder来自onLayoutChildren来自LayoutManager,我尝试覆盖它并在其notifyItemInserted之后调用super但我得到了同样的例外

我如何实现目标?

6 个答案:

答案 0 :(得分:44)

        Handler handler = new Handler();

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

        handler.post(r);

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

答案 1 :(得分:20)

同样值得注意的是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或a来推迟更改   类似的机制。

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

答案 2 :(得分:9)

使用Handler添加项目并从notify...()调用Handler为我解决了问题。

答案 3 :(得分:5)

整洁轻松方式:

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

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

答案 4 :(得分:1)

试试这个

if (!recyclerView.isComputingLayout()) {
        recyclerView.notifyDataSetChanged();
    }

答案 5 :(得分: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);
            }
        });
    }
}