SHOEISHA iD

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

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

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

LiveData/Flowを自働生成するRoomの仕組みを理解しよう!──Kotlin専用「Flow」も解説

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

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

Roomに備わるLiveDataの生成機能とは

 では、このリスト表示用のLiveDataをどのように用意するかに話を移していきます。まず、リストデータは各要素がCocktailmemoエンティティで表されることから、リストデータそのもののデータ型は、List<Cocktailmemo>となります。これをジェネリクスとして型指定するため、MainViewModelでのリストデータLiveDataに関連するコードは、Javaではリスト1、Kotlinではリスト2のようになります。

リスト1:MainViewModelのリストデータ用LiveData関連コード(Java版)
public class MainViewModel extends AndroidViewModel {
  private LiveData<List<Cocktailmemo>> _cocktailmemoListLiveData;
    :
  public MainViewModel(Application application) {
    :
    _cocktailmemoListLiveData = _cocktailmemoRepository.getCocktailmemoList();
  }
    :
  //_cocktailmemoListLiveDataフィールドのゲッタ。
  public LiveData<List<Cocktailmemo>> getCocktailmemoListLiveData() {
    return _cocktailmemoListLiveData;
  }
}
リスト2:MainViewModelのリストデータ用LiveData関連コード(Kotlin版)
class MainViewModel(application: Application) : AndroidViewModel(application) {
  val cocktailmemoListLiveData: LiveData<MutableList<Cocktailmemo>>
    :
  init {
    :
    cocktailmemoListLiveData = _cocktailmemoRepository.getCocktailmemoList()
  }
    :
}

 JavaでもKotlinでも、フィールド/プロパティでLiveData<List<Cocktailmemo>>型の_cocktailmemoListLiveDataを用意し、コンストラクタで、CocktailmemoRepositoryのgetCocktailmemoList()メソッドを利用して、その中身を取得しています。

 前回のCocktailmemo単体のLiveData(LiveData<Cocktailmemo>)であるcocktailmemoLiveDataに対して、CocktailmemoRepositoryから取得したカクテルメモ情報をsetValue()メソッド(Javaコード)、あるいは、valueプロパティ(Kotlinコード)を利用してMainViewModel内で格納していました。今回は、そのようなコードではなく、CocktailmemoRepositoryのgetCocktailmemoList()メソッドの戻り値を直接格納しています。このgetCocktailmemoList()メソッドのコードは、Javaではリスト3、Kotlinではリスト4のようになります。

リスト3:CocktailmemoRepositoryのgetCocktailmemoList()(Java版)
public class CocktailmemoRepository {
    :
  public LiveData<List<Cocktailmemo>> getCocktailmemoList() {
    CocktailmemoDAO cocktailmemoDAO = _db.createCocktailmemoDAO();
    return cocktailmemoDAO.findAll();
  }
    :
}
リスト4:CocktailmemoRepositoryのgetCocktailmemoList()(Kotlin版)
class CocktailmemoRepository(application: Application) {
    :
  fun getCocktailmemoList(): LiveData<MutableList<Cocktailmemo>> {
    val cocktailmemoDAO = _db.createCocktailmemoDAO()
    return cocktailmemoDAO.findAll()
  }
    :
}

 もちろん、ここで実行しているCocktailmemoDAOのfindAll()は、RoomのDAOインターフェースのメソッドであり、ここでもそのfindAll()の戻り値をそのままリターンする処理のみとなっています。そして、そのCocktailmemoDAOのfindAll()の定義は、Javaではリスト5のように、Kotlinではリスト6のようになります。

リスト5:CocktailmemoDAOのfindAll()の定義(Java版)
@Dao
public interface CocktailmemoDAO {
  @Query("SELECT * FROM cocktailmemos")
  LiveData<List<Cocktailmemo>> findAll();
    :
}
リスト6:CocktailmemoDAOのfindAll()の定義(Kotlin版)
@Dao
interface CocktailmemoDAO {
  @Query("SELECT * FROM cocktailmemos")
  fun findAll(): LiveData<MutableList<Cocktailmemo>>
    :
}

 ここで注目すべきは、findAll()メソッドの戻り値のデータ型です。Roomでは、そもそもLiveDataの生成機能が備わっており、その機能を利用する場合は、単に戻り値のデータ型をLiveDataとするだけです。これで、SELECTの結果、ここでは、カクテル情報のリストデータが丸ごとLiveDataとして扱われます。わざわざ手動でリストデータをLiveDataに格納する必要がないのです。

RecyclerViewを変更するオブザーバ登録

 このように、RoomのLiveData生成機能を利用すれば、特別なコーディングをせずとも簡単にLiveDataが用意できます。次に、このLiveDataにオブザーバを登録して、リスト表示させます。

 リスト部分をRecyclerViewで表示させるとすると、アダプタクラスが必要です。このアダプタクラスをCocktailListAdapterとすると、その構造は、Javaではリスト7のように、Kotlinではリスト8のようになります。

リスト7:CocktailListAdapter(Java版)
private class CocktailListAdapter extends RecyclerView.Adapter<CocktailmemoViewHolder> {
  private List<Cocktailmemo> _cocktailmemoList = new ArrayList<>();  // (1)
  @NonNull
  @Override
  public CocktailmemoViewHolder onCreateViewHolder(…) {
    :
  }
  @Override
  public void onBindViewHolder(…) {
    :
  }
  @Override
  public int getItemCount() {
    return _cocktailmemoList.size();
  }
  public void changeCocktailmemoList(List<Cocktailmemo> cocktailmemoList) {  // (2)
    _cocktailmemoList = cocktailmemoList;  // (3)
    notifyDataSetChanged();  // (4)
  }
}
リスト8:CocktailListAdapter(Kotlin版)
private inner class CocktailListAdapter() : RecyclerView.Adapter<CocktailmemoViewHolder>() {
  private var _cocktailmemoList: MutableList<Cocktailmemo> = mutableListOf()  // (1)
  override fun onCreateViewHolder(…): CocktailmemoViewHolder {
    :
  }
  override fun onBindViewHolder(…) {
    :
  }
  override fun getItemCount(): Int {
    return _cocktailmemoList.size
  }
  fun changeCocktailmemoList(cocktailmemoList: MutableList<Cocktailmemo>) {  // (2)
    _cocktailmemoList = cocktailmemoList  // (3)
    notifyDataSetChanged()  // (4)
  }
}

 注目すべきは、(2)のメソッドです。CocktailListAdapterでは、(1)で保持したリストデータをデータセットとしてリスト表示されるようにコーディングしています。そして、(2)では、リスト表示に必要な新たなリストデータを引数で受け取り、それを(3)で(1)のリストデータに代入する処理を記述しています。さらに、(4)のnotifyDataSetChanged()メソッドを実行することで、新たなデータセットをもとに、リスト表示を再描画する処理となっています。

 このchangeCocktailmemoList()を、LiveDataに登録するオブザーバの中で呼び出すことで、リストの再描画を行うようにします。となると、オブザーバクラスをCocktailmemoListObserverとすると、このクラスは、Javaではリスト9のように、Kotlinではリスト10のようになります。

リスト9:CocktailmemoListObserverクラス(Java版)
public class MainActivity extends AppCompatActivity {
  :
  private class CocktailmemoListObserver implements Observer<List<Cocktailmemo>> {
    @Override
    public void onChanged(@NonNull List<Cocktailmemo> cocktailmemos) {
      _cocktailListAdapter.changeCocktailmemoList(cocktailmemos);
    }
  }
}
リスト10:CocktailmemoListObserverクラス(Kotlin版)
class MainActivity : AppCompatActivity() {
  :
  private inner class CocktailmemoListObserver : Observer<MutableList<Cocktailmemo>> {
    override fun onChanged(cocktailmemos: MutableList<Cocktailmemo>) {
      _cocktailListAdapter.changeCocktailmemoList(cocktailmemos)
    }
  }
}

 特に説明不要なほどシンプルなコードであり、単に_cocktailListAdapterのchangeCocktailmemoList()メソッドを実行しているだけです。その際、新しいリストデータがonChanged()メソッドの引数cocktailmemosとして渡されるので、そのcocktailmemosをそのままchangeCocktailmemoList()に渡しています。ただし、オブザーバクラス内のコードがこのようなコードとなるため、_cocktailListAdapterはMainActivityのフィールド/プロパティとして保持しておく必要がある点には注意してください。

次のページ
Kotlin専用の仕組み「Flow」とは

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

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

もっと読む

この記事の著者

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

静岡県榛原町生まれ。一橋大学経済学部卒業後、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編 」他、著書多数

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

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

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

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

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

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/18156 2023/08/29 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング