見出し画像

【JetpackCompose】Roomを使ってTodoアプリを作ろう

注意: この記事にはリメイク版があります。

こんにちはまっこりです。今回のnoteはAndoridアプリ開発のチュートリアル記事です。SQLiteを扱うためのライブラリであるRoomを使ってTodoアプリを作っていきます。Roomを使ったCRUDの実装方法と、MVVM+Rアーキテクチャの実装方法を学べる内容となっています。

完成版のソースコードはGitHubにアップロードしてあります。必要な場合は参照してください。

開発環境
Android Studioバージョン: Chipmunk 2021.2.1 Patch 1
Roomバージョン: 2.4.2

1. 新規プロジェクトの作成

コードを書いていく前に、プロジェクトの作成と簡単なセットアップをしていきます。

テンプレート選択

まずはプロジェクトを作成します。
プロジェクトテンプレートは「Empty Compose Activity」を選択して、アプリ名は「RoomTodo」と設定しましょう。

不要なテンプレートの削除

プロジェクトが作成されたら、テンプレートに含まれている余分なコードを消してしましましょう。

MainActivity.ktを開いて、以下のGreeting関数とDefaultPreview関数を消してください。また、Greetingを呼び出しているコードも削除してください。

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    RoomTodoTheme {
        Greeting("Android")
    }
}

依存関係の追加

Roomを使用するので、Roomの依存関係を追加します。Moduleレベルのbuild.gradleファイルを開いて、dependenciesブロックの中に以下の依存関係を追加してください。

def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"

また、同じファイルのpluginsブロックに以下の一行を追加してください。

id 'kotlin-kapt'

これでプロジェクトの作成とセットアップは完了です。ここで一度エミュレータか実機で動作確認してみましょう。

ここまでのコードはこちら

2. エンティティの作成

この章では、データベースのテーブル構造を表すデータエンティティを作成します。

Todoエンティティ

Todoリスト一件に該当するエンティティを作成します。Todoリスト一件のデータに必要な項目とデータタイプは以下のようになります。

  • id - (Integer, PrimaryKey, Auto Increment)

  • title - (String)

  • description - (String)

エンティティクラスの作成

Todoエンティティを作っていきます。MainActivity.ktと同じディレクトリにTodo.ktという名前でKotlinDataクラスファイルを作成してください。ファイルを作成したら、以下のようにコードを追加してください。

data class Todo(
    val id: Int,
    val title: String,
    val description: String,
)

もちろん、これだけだとRoomのエンティティとしては認識されません。Roomのアノテーションをつけていきます。

@Entity
data class Todo(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val title: String,
    val description: String,
)

Roomはデフォルトだとエンティティのクラス名をテーブル名、プロパティ名をカラム名としてテーブルを作成するので、これでtodoテーブルの定義は完了です。

ここまでのソースコードはこちら。

クラス名と違うテーブル名やプロパティ名と違うカラム名を設定する方法もありますので、その辺を知りたい方はdeveloperサイトを見てみてください。

3. DAOの作成

テーブルを定義するエンティティの作成が完了したので、次はData Access Object(DAO)を作っていきます。DAOはデータベースへのCreate, Read, Update, Delete操作を行うインターフェースを提供します。

CRUDインターフェースの追加

MainActivity.ktと同じディレクトリにTodoDao.ktという名前でKotlinインターフェースファイルを作成してください。

interface TodoDao {
}

ここに、TodoのCRUDに対応するインターフェースを定義していきます。以下のようにTodoDaoを変更してください。

@Dao
interface TodoDao {
    // Create
    @Insert
    fun insertTodo(todo: Todo)

    // Read
    @Query("SELECT * FROM Todo")
    fun getAllTodos(): List<Todo>

    // Update
    @Update
    fun updateTodo(todo: Todo)

    // Delete
    @Delete
    fun deleteTodo(todo: Todo)
}

これで、Todoエンティティに対するCRUD操作を行うインターフェースの実装できました。各関数に付与しているアノテーションをもとにRoomがSQLiteデータベースの操作するためのコードを自動生成してくれます。

suspend修飾子の追加

データベースとのやりとりは非同期で行いたいため、今回はcoroutineを使って、CRUD操作を非同期で行うようにします。各関数にsuspend修飾子を付けましょう。

@Dao
interface TodoDao {
    // Create
    @Insert
    suspend fun insertTodo(todo: Todo)

    // Read
    @Query("SELECT * FROM Todo")
    suspend fun getAllTodos(): List<Todo>

    // Update
    @Update
    suspend fun updateTodo(todo: Todo)

    // Delete
    @Delete
    suspend fun deleteTodo(todo: Todo)
}

以上でTodoDaoの作成は完了です。ここまでのソースコードはこちら。

4. Roomデータベースの追加

次は、RoomDatabaseの実装したTodoDatabaseとそのインスタンスを取得するためのコードを作成します。TodoDatabaseインスタンスがSQLiteで永続化しているデータに対するアクセスポイントになります。

TodoDatabaseの作成

まずは、TodoDatabaseクラスを作成します。MainActivity.ktと同じフォルダに、TodoDatabaseという名前でKotlinクラスファイルを作成し、以下のようにコードを追加してください。

@Database(entities = [Todo::class], version = 1)
abstract class TodoDatabase: RoomDatabase() {
    abstract fun todoDao(): TodoDao
}

Helper関数を追加

これでTodoDatabaseの作成は完了です。TodoDatabaseインスタンスを取得するためのhelper関数を追加しましょう。

@Database(entities = [Todo::class], version = 1)
abstract class TodoDatabase: RoomDatabase() {
    abstract fun todoDao(): TodoDao

    // 以下を追加
    companion object {
        private var INSTANCE: TodoDatabase? = null

        fun getInstance(context: Context): TodoDatabase {
            synchronized(this) {
                var instance = INSTANCE

                if (instance == null) {
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        TodoDatabase::class.java,
                        "todo_database"
                    ).fallbackToDestructiveMigration()
                        .build()

                    INSTANCE = instance
                }
                return instance
            }
        }
    }
}

getInstanceでTodaDatabaseへの参照を取得することができます。また、TodoDatabaseインスタンスが二つ以上生成されないようにすることができます。

ここまでのソースコードはこちら。

5. Repositoryの作成

ここまでで、Roomデータベースの定義とセットアップが完了したので、次はRepositoryを作っていきます。RepositoryではTodoのCRUDに対応した関数を作成します。

MainActivity.ktと同じディレクトリにTodoRepository.ktという名前でKotlinクラスファイルを追加して、以下のようにコードを追加してください。

class TodoRepository(private val todoDao: TodoDao) {
    /** Create. */
    suspend fun createTodo(todo: Todo) {
        todoDao.insertTodo(todo)
    }

    /** Read. */
    suspend fun getAllTodo(): List<Todo> {
        return todoDao.getAllTodos()
    }

    /** Update. */
    suspend fun updateTodo(todo: Todo) {
        todoDao.updateTodo(todo)
    }

    /** Delete. */
    suspend fun deleteTodo(todo: Todo) {
        todoDao.deleteTodo(todo)
    }
}

以上でRepositoryの追加は完了です。今回は非常にシンプルなTodoアプリのためTodoRepositoryはTodoDaoのラッパークラスにすぎない状態になっていますが、本来は、データのキャッシングやデータソースの振り分け、エラーイベントの発火処理などをここで実装します。

ここまででRepository層の実装は完了しました。次の章からはViewModelの実装に入っていきます。

この章の変更内容はこちら。

6. ViewModelの作成

ここから先は

19,100字 / 4画像
この記事のみ ¥ 250

この記事が気に入ったらチップで応援してみませんか?