Roomに備わるLiveDataの生成機能とは
では、このリスト表示用のLiveDataをどのように用意するかに話を移していきます。まず、リストデータは各要素がCocktailmemoエンティティで表されることから、リストデータそのもののデータ型は、List<Cocktailmemo>となります。これをジェネリクスとして型指定するため、MainViewModelでのリストデータLiveDataに関連するコードは、Javaではリスト1、Kotlinではリスト2のようになります。
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; } }
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のようになります。
public class CocktailmemoRepository { : public LiveData<List<Cocktailmemo>> getCocktailmemoList() { CocktailmemoDAO cocktailmemoDAO = _db.createCocktailmemoDAO(); return cocktailmemoDAO.findAll(); } : }
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のようになります。
@Dao public interface CocktailmemoDAO { @Query("SELECT * FROM cocktailmemos") LiveData<List<Cocktailmemo>> findAll(); : }
@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のようになります。
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) } }
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のようになります。
public class MainActivity extends AppCompatActivity { : private class CocktailmemoListObserver implements Observer<List<Cocktailmemo>> { @Override public void onChanged(@NonNull List<Cocktailmemo> cocktailmemos) { _cocktailListAdapter.changeCocktailmemoList(cocktailmemos); } } }
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のフィールド/プロパティとして保持しておく必要がある点には注意してください。