title: Recyclerview - cannot call this method in a scroll callback
body: <p>I have seen this question many times in StackOverflow, but I couldn't get the issue fixed. So reaching out for help.   </p>
  
  <p><em>Please note: I have already checked other questions on SO and though I could get rid of the error, there are other issues with it.</em></p>
  
  <p>Here is my existing code:</p>
  
  <p>My Adapter class:</p>
  
  <pre><code>  public class RecyclerViewAdapter extends RecyclerView.Adapter&lt;RecyclerView.ViewHolder&gt; {
  
          Context context;
  
          private final int VIEW_TYPE_ITEM = 0;
          private final int VIEW_TYPE_LOADING = 1;
          private IOnLoadMoreListener mIOnLoadMoreListener;
  
          private int visibleThreshold = 3;
          private int lastVisibleItem, totalItemCount;
          private int[] lastVisibleItems = new int[mStaggeredLayoutManager.getSpanCount()];
  
          public RecyclerViewAdapter(Context context) {
              this.context = context;
  
              final StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
  
              recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                  @Override
                  public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                      super.onScrolled(recyclerView, dx, dy);
  
                      totalItemCount = staggeredGridLayoutManager.getItemCount();
                      lastVisibleItems = staggeredGridLayoutManager.findLastVisibleItemPositions(new int[mStaggeredLayoutManager.getSpanCount()]);
  
                      if (staggeredGridLayoutManager.getSpanCount() == 1) {
                          lastVisibleItem = lastVisibleItems[0];
                      } else if (staggeredGridLayoutManager.getSpanCount() == 2) {
                          lastVisibleItem = Math.max(lastVisibleItems[0], lastVisibleItems[1]);
                      } else if (staggeredGridLayoutManager.getSpanCount() == 3) {
                          lastVisibleItem = Math.max(Math.max(lastVisibleItems[0], lastVisibleItems[1]), lastVisibleItems[2]);
                      }
  
                      if (!isRefreshing &amp;&amp; totalItemCount &lt;= lastVisibleItem + visibleThreshold) {
  
                          if (mIOnLoadMoreListener != null) {
                              mIOnLoadMoreListener.onLoadMore();
                          }
  
                          isRefreshing = true;
                      }
                  }
              });
  
          }
  
          @Override
          public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  
              if (viewType == VIEW_TYPE_ITEM) {
  
                  View v = LayoutInflater.from(parent.getContext())
                          .inflate(R.layout.item_recyclerview_shop_fragment, parent, false);
                  return new CustomViewHolder(v);
              } else if (viewType == VIEW_TYPE_LOADING) {
  
                  View v = LayoutInflater.from(parent.getContext())
                          .inflate(R.layout.item_recyclerview_loading_shop_fragment, parent, false);
                  return new LoadingViewHolder(v);
              }
  
              return null;
          }
  
          @Override
          public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
  
              Product item = listItems.get(position);
  
              if (holder.getItemViewType() == VIEW_TYPE_ITEM) {
  
                  CustomViewHolder customViewHolder = (CustomViewHolder) holder;
                  Glide.with(context).load(item.getFeaturedSrc()).into(customViewHolder.imageView);
  
              } else if (holder.getItemViewType() == VIEW_TYPE_LOADING) {
  
                  if (holder instanceof LoadingViewHolder) {
                      LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
                      loadingViewHolder.progressBar.setIndeterminate(true);
                  }
              }
  
  
          }
  
          @Override
          public int getItemCount() {
              return listItems == null ? 0 : listItems.size();
          }
  
          @Override
          public int getItemViewType(int position) {
  
              if (listItems.get(position) == null) {
                  return VIEW_TYPE_LOADING;
              } else {
                  return VIEW_TYPE_ITEM;
              }
          }
  
          public void setOnLoadMoreListener(IOnLoadMoreListener mIOnLoadMoreListener) {
              this.mIOnLoadMoreListener = mIOnLoadMoreListener;
          }
  
  
          public class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
  
              ImageView imageView;
              TextView textView;
  
              String id;
  
              public CustomViewHolder(View itemView) {
                  super(itemView);
  
                  itemView.setOnClickListener(this);
                  imageView = (ImageView) itemView.findViewById(R.id.imageView_thumbnail);
  
              }
  
              @Override
              public void onClick(View v) {
  
                  int position = getAdapterPosition();
  
              }
          }
  
          public class LoadingViewHolder extends RecyclerView.ViewHolder {
              public ProgressBar progressBar;
  
              public LoadingViewHolder(View progressView) {
                  super(progressView);
                  progressBar = (ProgressBar) progressView.findViewById(R.id.progressBar);
              }
          }
  
      }
  </code></pre>
  
  <p>My previous code:</p>
  
  <pre><code>   mRecyclerViewAdapter.setOnLoadMoreListener(new IOnLoadMoreListener() {
          @Override
          public void onLoadMore() {
  
              listItems.add(null);
  
              mRecyclerViewAdapter.notifyItemChanged(listItems.size() - 1);
              mRecyclerViewAdapter.notifyDataSetChanged();
  
              isProgressVisible = true;
  
              getDataFromServer(false);
  
          }
      });
  </code></pre>
  
  <p>With my old code, I get the following IllegalStateException:</p>
  
  <pre><code>W/RecyclerView: Cannot call this method in a scroll callback. Scroll callbacks mightbe run during a measure &amp; layout pass where you cannot change theRecyclerView data. Any method call that might change the structureof the RecyclerView or the adapter contents should be postponed tothe next frame.
  java.lang.IllegalStateException: 
  
  at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:2581)
  at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeChanged(RecyclerView.java:4943)
  at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(RecyclerView.java:11373)
  at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(RecyclerView.java:11364)
  at android.support.v7.widget.RecyclerView$Adapter.notifyItemChanged(RecyclerView.java:6652)
  at codsiga.com.xx.ShopFragment$1.onLoadMore(ShopFragment.java:148)
  at codsiga.com.xx.ShopFragment$RecyclerViewAdapter$1.onScrolled(ShopFragment.java:229)
  at android.support.v7.widget.RecyclerView.dispatchOnScrolled(RecyclerView.java:4618)
  at android.support.v7.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:3679)
  at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3323)
  at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3844)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
  at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:636)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1795)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:131)
  at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
  at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1391)
  at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:870)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1079)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
  at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
  at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
  
  03-22 11:36:32.083 3189-3189/codsiga.com.xx W/RecyclerView:    
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
  at com.android.internal.policy.DecorView.onLayout(DecorView.java:726)
  at android.view.View.layout(View.java:17637)
  at android.view.ViewGroup.layout(ViewGroup.java:5575)
  at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2346)
  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2068)
  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6337)
  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
  at android.view.Choreographer.doCallbacks(Choreographer.java:686)
  at android.view.Choreographer.doFrame(Choreographer.java:621)
  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
  at android.os.Handler.handleCallback(Handler.java:751)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:154)
  at android.app.ActivityThread.main(ActivityThread.java:6119)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
  </code></pre>
  
  <p>So as suggested on various StackOverflow answers, I modified it like below:</p>
  
  <p>modified code looking at various answers:</p>
  
  <pre><code>mRecyclerViewAdapter.setOnLoadMoreListener(new IOnLoadMoreListener() {
              @Override
              public void onLoadMore() {
  
                  recyclerView.post(new Runnable() {
                      @Override
                      public void run() {
  
                          listItems.add(null);
  
                          mRecyclerViewAdapter.notifyItemChanged(listItems.size() - 1);
                          mRecyclerViewAdapter.notifyDataSetChanged();
  
                          isProgressVisible = true;
  
                          getDataFromServer(false);
  
  
                      }
                  });
              }
          });
  </code></pre>
  
  <p>Now, I don't get the error, but the <code>onLoadMore()</code> is called twice, everytime and the views in recyclerview keep refreshing everytime. What is it I am doing wrong? Please see the logcat output:</p>
  
  <pre><code>D/xx: Response =&gt; {…}
  D/xx: Length = 9
  D/xx: Query 'SELECT * FROM products' returned 9 rows
  
  D/xx: Response =&gt; {…}
  D/xx: Length = 9
  D/xx: Query 'SELECT * FROM products' returned 18 rows
  </code></pre>