SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

一歩進んだAndroidアプリ開発ができる「Android Jetpack」入門

「ページングライブラリ」でデータベースにキャッシュしながらページングする方法

一歩進んだAndroidアプリ開発ができる「Android Jetpack」入門 第14回


  • X ポスト
  • このエントリーをはてなブックマークに追加

Java版RemoteMediatorのコーディングとその利用方法

 Kotlin版の紹介が終了したので、Java版に話を移します。

JavaではListenableFutureRemoteMediatorを継承

 Java版のPhoneRemoteMediatorはリスト4のようになります。

[リスト4]data/remote/PhoneRemoteMediator.java
@OptIn(markerClass = ExperimentalPagingApi.class)
public class PhoneRemoteMediator extends ListenableFutureRemoteMediator<Integer, Phone> {  // (1)
  private final AppDatabase _db;
  public PhoneRemoteMediator(AppDatabase db) {
    _db = db;
  }
  @NotNull
  @Override
  public ListenableFuture<MediatorResult> loadFuture(@NonNull LoadType loadType, @NonNull PagingState<Integer, Phone> pagingState) {  // (2)
    //戻り値変数を用意。
    ListenableFuture<MediatorResult> returnVal;
    PhoneDAO phoneDAO = _db.createPhoneDAO();
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    try {
      //loadTypeで処理を分岐。
      switch(loadType) {
        //データクリアの場合。
        case REFRESH:
          ListenableFuture<Integer> deleteResultFuture = phoneDAO.deleteAll();
          deleteResultFuture.get();
          returnVal = Futures.immediateFuture(new MediatorResult.Success(false));  // (3)
          break;
        //データの末尾を検知した場合。
        case PREPEND:
          returnVal = Futures.immediateFuture(new MediatorResult.Success(true));  // (4)
          break;
        //データの先頭を検知した場合。
        default:
          //データベース内のidの最大ちからstartKeyとendKeyを決定。
          ListenableFuture<Long> lastIdFuture = phoneDAO.findLastId();
          Long lastIdL = lastIdFuture.get();
          long lastId = 0;
          if(lastIdL != null) {
            lastId = lastIdL;
          }
          long startKey = lastId + 1;
          long endKey = startKey + pagingState.getConfig().pageSize - 1;
          //ネット上から追加のリストを取得しデータベースに格納。
          PhoneListFetcher phoneListFetcher = new PhoneListFetcher(startKey, endKey);
          Future<List<Phone>> phoneListFuture = executorService.submit(phoneListFetcher);
          List<Phone> phoneList = phoneListFuture.get();
          ListenableFuture<List<Long>> insertResultFuture = phoneDAO.insertPhoneList(phoneList);
          insertResultFuture.get();
          //ネット上からリストサイズを取得してリスに続きがあるかどうかを判定。
          PhoneListSizeFetcher phoneListSizeFetcher = new PhoneListSizeFetcher();
          Future<Integer> listSizeFuture = executorService.submit(phoneListSizeFetcher);
          int listSize = listSizeFuture.get();
          MediatorResult result;
          if (endKey < listSize) {
            result = new MediatorResult.Success(false);
          }
          else {
            result = new MediatorResult.Success(true);
          }
          returnVal = Futures.immediateFuture(result);  // (5)
          break;
      }
    }
    catch(Exception ex) {
      returnVal = Futures.immediateFuture(new MediatorResult.Error(ex));  // (6)
    }
    return returnVal;
  }
}

 基本的には、リスト2のコードをJavaに置き換えた内容になっています。ただし、大きな違いがリスト4の(1)にあるように、RemoteMediatorではなくListenableFutureRemoteMediatorを継承することです。その理由は非同期処理に対応するためで、前回のリスト5でPhonePagingSourceの親クラスをListenableFuturePagingSourceとしたのと同様です。

 それに伴い、load()メソッドもその名称が変わり、(2)のようにloadFuture()となります。また、その戻り値もMediatorResultをListenableFutureでラップしたListenableFuture<MediatorResult>となります。

 そのため、戻り値のreturnValに値を格納する各コードは(3)(4)(5)および(6)のように、Futures.immediateFuture()を実行してListenableFutureでラップしています。このコードパターンも、前回のリスト5と同様です。

リポジトリではPagerコンストラクタの第3引数にとして渡す

 最後に、リポジトリでのRemoteMediatorを利用するコードパターンのJava版を紹介します。これは、リスト5のようになります。

[リスト5]data/repository/PhoneRepository.java
@OptIn(markerClass = ExperimentalPagingApi.class)
public Pager<Integer, Phone> getAllPhoneListPager() {
  PhoneDAO phoneDAO = _db.createPhoneDAO();
  PagingConfig pagingConfig = new PagingConfig(ITEMS_PER_PAGE);
  PhoneRemoteMediator phoneRemoteMediator = new PhoneRemoteMediator(_db);
  Pager<Integer, Phone> phoneListPager = new Pager<>(pagingConfig, null, phoneRemoteMediator, () -> phoneDAO.findAll());
  return phoneListPager;
}

 これも、リスト5のコードをJavaコードに置き換えたコードとなっており、特に問題ないと思います。

まとめ

 Android Jetpackについて紹介していく本連載の第14回は、いかがでしたでしょうか。

 今回は、ページングライブラリを利用して、ネット上にあるリストデータをデータベースにキャッシュしながらページングする方法を紹介しました。次回は、ナビゲーションを紹介します。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
一歩進んだAndroidアプリ開発ができる「Android Jetpack」入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。Web系製作会社のシステム部門、SI会社を経てフリーランスとして独立。屋号はSarva(サルヴァ)。HAL大阪の非常勤講師を兼務。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/21385 2025/04/25 17:53

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング