読者です 読者をやめる 読者になる 読者になる

visible true

技術的なメモを書く

rxbinding-recyclerview-v7とPublishSubjectを使ってRecyclerViewでスクロールが一番下まで行ったらロードする実装

すでにある気がするけど見当たらなかったのでメモ。

ソース

こちらにあります。

GitHub - sys1yagi/rxrecyclerview-load-more

準備

rxbinding-recyclerview-v7をdependenciesに追加する。

dependencies {
  compile 'com.jakewharton.rxbinding:rxbinding-recyclerview-v7:0.4.0'
}

RxRecyclerViewScrollSubjectを作る

RxRecyclerViewを使ってRecyclerViewScrollEventを受け取り、LinearLayoutManagerを使って最後尾かどうかの判定をします。メソッドは3つだけです。

public class RxRecyclerViewScrollSubject {
  Subject<RecyclerViewScrollEvent, RecyclerViewScrollEvent> subject = PublishSubject.create();
  Subscription subscription = Subscriptions.empty();

  public Observable<RecyclerViewScrollEvent> observable() {
    return subject;
  }

  public void start(RecyclerView recyclerView, LinearLayoutManager linearLayoutManager) {
    subscription.unsubscribe();
    subscription = RxRecyclerView.scrollEvents(recyclerView).subscribe(event -> {
      int totalItemCount = linearLayoutManager.getItemCount();
      int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
      if (totalItemCount - 1 <= lastVisibleItemPosition) {
        subject.onNext(event);
      }
    });
  }

  public void stop() {
    subscription.unsubscribe();
  }
}

GridLayoutManagerはLinearLayoutManagerを継承しているのでそのまま使えます。StaggeredGridLayoutManagerは継承関係がないのでfindLastVisibleItemPosition()が存在せずそのまま使えません。似たようなメソッドがあるので別途StaggeredGridLayoutManagerを受け取る口を作っとくといいかもしれないです。

使う

ライフサイクルに合わせてRxRecyclerViewScrollSubjectをstart()したりstop()します。

public class MainActivity extends AppCompatActivity {
  RxRecyclerViewScrollSubject rxRecyclerViewScrollSubject = new RxRecyclerViewScrollSubject();
  RecyclerView recyclerView;
  LinearLayoutManager linearLayoutManager;
  Subscription subscription = Subscriptions.empty();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    //省略
  }

  @Override
  protected void onResume() {
    super.onResume();
    rxRecyclerViewScrollSubject
                .start(recyclerView, linearLayoutManager);
  }

  @Override
  protected void onPause() {
    super.onPause();
    rxRecyclerViewScrollSubject.stop();
  }
}

初回の読み込みが終わったらRxRecyclerViewScrollSubject.observable()をsubscribeし、イベントが来たらunsubscribeして追加読み込みをし、追加読み込みが完了したら再度subscribeするといった使い方になります。

void loadWhenLastPosition(int nextPage) {
  subscription = rxRecyclerViewScrollSubject.observable().subscribe(event -> {
            subscription.unsubscribe();
            load(nextPage);
        });
}

追加読み込みを開始したら最後尾のスクロール通知を切り、また通知して欲しくなったらsubscribeする感じです。

最後に

もっとなんかいい方法ある気もしつつ。