LoginSignup
1
1

More than 5 years have passed since last update.

OnScrollListener#onScrolled()のコールバックでエラーになる

Last updated at Posted at 2017-10-19

はじめに

RecyclerViewを使って何らかのデータをリスト表示する時にリストの最後尾を表示したタイミングで新しくデータをロードしたいことがあります。そういった場合RecyclerViewにOnScrollListenerをセットしてコールバック処理を実装します。このコールバック処理内で RecyclerView.Adapter#notifyDataSetChanged をすると次のような警告がでます。

Cannot call this method in a scroll callback. Scroll callbacks mightbe run during a measure & 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:2625)
    at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:4974)
    at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:11423)
    at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:6680)
...

警告がでる例

レイアウトは次のようなイメージ。

activity_main.xml
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>

実装は次のようなイメージ。

MainActivity.java
private SomeAdapter adapter;

public void initializeRecyclerView() {
    RecyclerView recyclerView = getActivity().findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager());
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            // loading...
            adapter.notifyDataSetChanged();
        }
    });
}

対策

コールバック部分を抜粋する。コールバック内で直接 notifyDataSetChanged をするのではなく一旦postすることで回避できます。

MainActivity.java
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    // loading...
    recyclerView.post(new Runnable() {
        @Override
        public void run() {
            adapter.notifyDataSetChanged();
        }
    });
}

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1