RecyclerView notifyItemInserted IllegalStateException

use*_*057 29 android android-5.0-lollipop android-recyclerview

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

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

路上,我实现了这个在我的BaseAdapter:getView所要求的接近尾声的观点,我将开始获取更多数据,请致电notifyDataSetChanged(获取进度视图显示),然后才返回所需的视图getView.

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

但如果我尝试notifyItemInserted在此方法内调用,我会得到以下异常:

IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
Run Code Online (Sandbox Code Playgroud)

我的尝试:我注意到,onBindViewHolder被称为从onLayoutChildrenLayoutManager,我尝试覆盖它并调用notifyItemInserted它之后super,但我得到了同样的异常

我怎样才能实现目标?

Raf*_*ael 44

        Handler handler = new Handler();

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

        handler.post(r);
Run Code Online (Sandbox Code Playgroud)

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


小智 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;
}
Run Code Online (Sandbox Code Playgroud)

显着的短语是:

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

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


cyb*_*gen 9

使用一个Handler添加项目和notify...()从这里调用Handler修复了我的问题.

  • 这是正确的答案,您无法在设置时更改项目(通过调用onBindViewHolder).在这种情况下,您必须通过调用Handler.post()在当前循环结束时调用notifyItemInserted (2认同)

Sha*_*ani 5

整洁简单的方法:

  recyclerView.post(new Runnable() {
                    @Override
                    public void run() {
                        adapter.notifyDataSetChanged();
                    }
                });
Run Code Online (Sandbox Code Playgroud)

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