データ更新処理
一般的に、RecyclerViewを使った画面のデータ更新処理は「初回画面表示した時に更新」「画面上部から引っ張って更新」と「一番下までスクロールしたら次のページを読み込む」の3つが考えられます。
先の2つは特に迷うことなくFragment#onResume()やSwipeRefreshLayout#setOnRefreshListener()でデータロード処理を呼び出すと良いでしょう。
3つ目の一番下までスクロールしたら次のページを読み込む処理については、RxJava+RxBinding (recyclerview-v7)ライブラリを利用すれば安全かつシンプルに実装できます。以下のコードに示す通り、データロード中に画面下部到達イベントを発生させない、イベントを重複して発生させないといった制約を課すことができます。
public class UserListFragment extends Fragment {
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
bindEvents();
}
...
/**
* イベントハンドラーを登録します。
*/
private void bindEvents() {
...
// RecyclerViewのスクロールイベント
RxRecyclerView.scrollEvents(mRecyclerView)
// ロード完了までは無視する
.skipUntil(mDataLoadedNotification)
// 最下部に達したら
.filter(REACH_BOTTOM)
// 一回だけ通知
.take(1)
// 通知が完了したら、またListenする
.repeat()
// 通知が開始されたら、プログレスダイアログ表示
.doOnNext(e -> ProgressDialogFragment.show(getFragmentManager()))
// ハンドラーを設定
.subscribe(this::onReachBottom);
}
...
/**
* リストの最下部到達イベントをハンドリングします。
*
* @param ignore {@link RecyclerViewScrollEvent}
*/
private void onReachBottom(final RecyclerViewScrollEvent ignore) {
loadUserList();
}
}
上記のコードで利用しているREACH_BOTTOMは、RecyclerViewScrollEventに対して最下部に達しているかどうかをチェックする述語(Predicateインターフェースの実装)です。RxBindingを使っていない場合であれば、RecyclerView.OnScrollListenerの実装クラスで似たような実装をしていると思います。
/**
* RecyclerViewのスクロールが最下部に達していることを判定する{@link Predicate}
*/
private static final Predicate<RecyclerViewScrollEvent> REACH_BOTTOM = e -> Optional.of(e)
// viewを取得
.map(RecyclerViewScrollEvent::view)
// レイアウトマネージャーを取得
.map(RecyclerView::getLayoutManager)
// LinearLayoutManagerへキャスト
.map(LinearLayoutManager.class::cast)
// 要素が1つ以上あるか?
.filter(lm -> lm.getItemCount() > 0)
// 最後の要素が見えているか?
.map(lm -> {
// 最終要素のインデックス
final int last = lm.getItemCount() - 1;
// 今見えている最終要素のインデックス
final int curr = lm.findLastCompletelyVisibleItemPosition();
return last <= curr;
}).orElse(false);
ここで利用したRxBinding (recylerview-v7)ライブラリは、build.gradleを以下のように設定する必要があります。こちらもProGuard設定は不要です。
dependencies {
...略...
compile 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'
...略...
}
最後に
Android 8.0、Android Studio 3.0とReactive Extensions(RxJava2)を中心として、有用なライブラリを用いたAndroidアプリ開発について、チャットアプリケーションを題材として解説しました。特にdesugarによるJava 8ビルド環境は、RetroLambdaを利用する場合の問題点(メソッド数の増加、Java 8コードを含むサードパーティライブラリは利用不可)を解決します。Jackがサポート終了になってしまったことも考慮すれば、しばらくデファクトスタンダードとして君臨するのではないでしょうか。この機会にRetroLambdaやJackから移行してみてはいかがでしょう。
また、RxJavaが開くReactive Extensionsの世界はAndroidアプリの開発においても有用なものが多くあります、RxをイベントのPub/Sub機構として捉えた場合、イベントそのものを途中で加工したり、イベントの流量を制御したりといったことが簡単に実装できるのが最も有用な点ではないでしょうか。
なお、添付のソースコードでは記事には書き切れなかった下記の実装も含んでいます。何かの参考になれば幸いです。
- Fragment間遷移でShared Elements Transition
- AndroidKeyStoreを使ったローカルへの暗号化データ保存
- XML上で調整可能な設定項目を有するカスタムView
developer.android.comのコンテンツ利用に伴う表記
Portions of this page are reproduced from work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.
