4
5

More than 3 years have passed since last update.

Roomでデータベースに値を保存

Last updated at Posted at 2020-05-27

はじめに

前回は、入力した値をリスト表示するところまで行いましいた。今回は、そのデータをデータベースに保存するようにします。

目標

Roomを追加するだけなので、今回はレイアウトの変更はありません。
アプリを閉じて、再起動したときにデータが保持されてるかを確認してください。

環境

  • Android Studio 3.6.3
  • Kotlin 1.3.72

作成手順

Gradle

build.gradle
apply plugin: 'kotlin-kapt'
...
dependencies {
    ...
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"

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

実装

Roomは以下の3つの要素で構成されています。
- Entity
- Dao (DataAccessObjects)
- Room Database

Entity

データベース内のテーブルを示します。
各Entityは、少なくとも一つの主キーを定義する必要があります。それは@PrimaryKeyアノテーションで定義できます。
autoGenerateを設定すると自動でPrimaryKeyを発行してくれます。

Todo.kt
@Entity
data class Todo(
    @PrimaryKey(autoGenerate = true) val tid: Int,
    @ColumnInfo(name = "todo_title") val todoTitle: String
)

Dao

Daoではデータベースにアクセスするためのメソッドを定義します。
Interfaceに@Daoをつけるだけで定義できます。
今回は、挿入と全データの取得を行うメソッドを定義しました。
getAll()の戻り値をLiveDataにすることにより、Roomがデータベースに変更があった場合に通知してくれる内部コードを生成してくれるらしいです。とても便利ですね。

TodoDao.kt
@Dao
interface TodoDao {

    @Insert
    suspend fun insert(todo: Todo)

    @Query("SELECT * FROM Todo")
    fun getAll(): LiveData<List<Todo>>
}

Database

データベースの定義では、抽象クラスに@Databaseをつけると定義できます。
先程定義したEntityをentitiesに指定します。
そしてDaoを取得するためのメソッドを用意します。

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

Repository

ViewModelとデータベースの中継としてRepositoryを作成します。

TodoRepository.kt
class TodoRepository(private val todoDao: TodoDao) {
    val allTodoList = todoDao.getAll()

    @WorkerThread
    suspend fun insert(todo: Todo) {
        todoDao.insert(todo)
    }
}

ViewModel

Repositoryからデータを受け取って処理します。
データベースの処理はメインスレッドで実行することができないので、Coroutineを使って非同期処理を行います。

MainViewModel.kt
class MainViewModel(private val repository: TodoRepository) : ViewModel() {
    val todoList = repository.allTodoList

    fun insert(todo: Todo) = viewModelScope.launch {
        repository.insert(todo)
    }
}

Activity

MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var mainViewModel: MainViewModel
    private lateinit var adapter: RecyclerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val db = Room.databaseBuilder(this, TodoDatabase::class.java, "database_name").build()
        val dao = db.todoDao()
        val repository = TodoRepository(dao)
        mainViewModel = MainViewModel(repository)

        adapter = RecyclerAdapter()
        main_recycler_view.layoutManager = LinearLayoutManager(this)
        main_recycler_view.adapter = adapter
        main_recycler_view.setHasFixedSize(true)

        add_item_button.setOnClickListener {
            mainViewModel.insert(Todo(0, submit_text.text.toString()))
        }

        mainViewModel.todoList.observe(this, Observer {
            adapter.setItem(it)
        })

    }
}

Adapter

新しく加えたデータをAdapterにセットします。

RecyclerAdapter.kt
class RecyclerAdapter : RecyclerView.Adapter<RecyclerAdapter.RecyclerViewHolder>(){

    private val todoList = mutableListOf<Todo>()

    fun setItem(items: List<Todo>) {
        todoList.clear()
        todoList.addAll(items)
        notifyDataSetChanged()
    }
    ...
}

おわりに

Roomを使用してデータベースに値を保存することができました。
次回は削除機能の追加をしたいと思います。
最近勉強したDaggerを使って、DIしてみてもいいかな!

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5