Android 基礎 -- Part 05 Datastore に保存するための　Repository の save メソッドを作成する
Published: 2023-01-12 15:32:11


## why

ステートに持った値を保存したい。
DB にはまだ繋がず、とりあえず Datastore に保存する。

Gauge のアプリでレスポンスを シナリオデータストアに入れていたように
Android でもデータストアに入れる。

https://www.youtube.com/watch?v=aQyphCXeVHg&list=PLgAI_5b_7BdRaBPAD5RMrzjoSwefDXpkw&index=7

SharedPreference という名前で使えるらしい。

---

## Datastore Preferences 1.0 をインポート

```kotlin
dependencies {
//...
    implementation 'androidx.datastore:datastore-preferences:1.0.0'
}
```

App の　build.gradle の dependecies の implementation で
androidx の datastore の datastore-preferences:1.0.0 
これを書き、 sync してインストールする

---

## Repository (Driver) を作成して Datastore に書き込めるようにする

https://www.youtube.com/watch?v=uvAbY38CNXU&list=PLgAI_5b_7BdRaBPAD5RMrzjoSwefDXpkw&index=8

コンポーザブルからは呼び出すだけで、処理担当を分ける。
実際にデータを書き込む処理は、Repository に書く。
クリーンアーキテクチャで言う、Driver 相応だろう。

現状、アプリのディレクトリ構造として

* screen / edit / EditNoteScreen.kt
* ui / theme / 
* MainActivity.kt
* NoteApp.kt

この構造になっている。

ここに package として repository / を追加する。
その中にインターフェースとして NoteRepository を作る。

Drive というより、インターフェースだから Port っぽいな

---

## インターフェースである reposotiry / NoteRepository で save と load を定義する

実装する前のインターフェースとして、クリーアーキテクチャで言う
Port のようなものを作る。実装と呼び出し先を繋げるものだ。

ここでは save と　load を作る。

```kotlin
package com.example.hellojetpack.repository

interface NoteRepository {
    suspend fun save(body: String)
    suspend fun load(): String
}
```

---

## インターフェースを TODO で実装する repository / datastore / DatastoreNoteRepository で save と　load を実装する。

とりあえず TODO で実装する。

実際の実装クラスを書く。
クリーンアーキテクチャでいう Driver のパッケージに書くものだ。

MokeLab さんのやり方では Repository パッケージの中に
さらに datastore パッケージを作って、中に書くらしい。

なので、先ほど作った　repository / のなかに datastore / を作って、その中に　DatastoreNoteRepositrory.kt を作った。

```kotlin
class DatastoreNoteRepository: NoteRepository {
    override suspend fun save(body: String) {
        TODO("Not yet implemented")
    }

    override suspend fun load(): String {
        TODO("Not yet implemented")
    }
}
```

中身は、NoteRepository のインターフェースを 
implement members してガワを作った。

---

## DatastoreNoteRepository のために Context に noteStore というプロパティを用意する。

https://www.youtube.com/watch?v=uvAbY38CNXU&list=PLgAI_5b_7BdRaBPAD5RMrzjoSwefDXpkw&index=8

この Android X のデータストアを使うためには Android の Context を使って、その中にプロパティを用意する必要があるらしい。

Context とは、React における Redex のような、どのコンポーザブルからでも読み書きのできる置き場所だと解釈する。

https://developer.android.com/topic/libraries/architecture/datastore?hl=ja#preferences-create

Kotlin ファイルの最上位、つまり一番最初にインスタンスが一度作られるらしい。そしてシングルトンで保持できるらしい。

https://e-words.jp/w/%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%83%88%E3%83%B3.html

シングルトンとは、一つしかインスタンスが作られないことで、つまり共通データにアクセスされるコンテキストのことだと解釈する。

```kotlin
import android.content.Context
import androidx.datastore.preferences.core.Preferences

val Context.noteStore: DataStore<Preferences> by preferencesDataStore(
    "note"
)
```

Android Context のなかに noteStore と言うプロパティを作成
型は先ほど依存に追加した Android X DataStore の Preferences とする。
これで Gauge で言う　Scenario Datastore のように
Android の Preference Datastore として
キーバリューストアが使えるようになると解釈した。

---

## PreferencesDatastore のための Preference Key を用意する

https://youtu.be/uvAbY38CNXU?t=200

```kotlin
val BODY_KEY = stringPreferenceKey("body")
```

データストアは キーバリュー　ストアなので
次はキーを作る。
Preference Datastore を作ったので、対応する
Preferecne Key を作った。

---

## Context.noteStore に Repository の save メソッドで引数のキーと中身の値が入るようにする。

```kotlin
val Context.noteStore: DataStore<Preferences> by preferencesDataStore(
    "note"
)

class DatastoreNoteRepository: NoteRepository {
    override suspend fun save(body: String) {
        TODO("Not yet implemented")
    }

    override suspend fun load(): String {
        TODO("Not yet implemented")
    }
}
```

現状、Preference の　Datastore を使って
Context に noteStore プロパティを生やしている。

save メソッドの中身には何もない。

```kotlin
class DatastoreNoteRepository(
    private val context: Context
): NoteRepository {
    override suspend fun save(body: String) {
        TODO("Not yet implemented")
    }
}
```

コンストラクタ インジェクションで
クラス生成時に一度だけ context インスタンスができるようにする。

```kotlin
    override suspend fun save(body: String) {
        context.noteStore.edit { pref ->
            pref[BODY_KEY]  = body
        }
    }
```

引数の body を
ストアの BODY_KEY と言うキーのバリューとして入れる。