【Kotlin/Android Studio】DataStoreの使い方!データの保存と取得方法

この記事からわかること
- Android Studio/KotlinでDataStoreを使った実装方法
- ローカルにデータを永続的に保存する方法
- アプリを停止してもデータを保持するには?
- 保存できるデータ型の種類
- Preferences DataStoreとProto DataStoreの違い
- No type arguments expected for class Flowの解決法
- Property delegate must have a 'getValue(Context, KProperty<*>)' method. None of the following functions is suitable:...の解決法
index
[open]
- DataStoreとは?
- SharedPreferencesは非推奨?
- Preferences DataStoreとProto DataStore
- Preferences DataStoreの使い方
- 依存関係の追加
- Datastore
のインスタンスを作成 - インスタンスに保存する必要がある各値のキーを定義
- データを保存する
- データを取得する
- Flowで取得して観測する
- 全体のコード
- DataStoreを管理するクラスを作成してみる
- Property delegate must have a 'getValue(Context, KProperty<*>)' method. None of the following functions is suitable:public abstract operator fun getValue(thisRef: Context, property: KProperty<*>): DataStore
defined in kotlin.properties.ReadOnlyProperty - No type arguments expected for class Flow
\ アプリをリリースしました /
参考文献:公式リファレンス:DataStore
環境
- Android Studio:Meerkat
- Kotlin:2.0.21
- DataStore:1.1.4
DataStoreとは?
AndroidのDataStoreはプロトコルバッファ(※)を使用してKey-Value形式や型付きオブジェクトをローカルに保存することができるJetpackのライブラリです。DataStoreを使用することでアプリを停止させても永続的にデータを保存し再度起動した時にもデータを再度取得することが可能になります。
※プロトコルバッファとはGoogleが開発した、データをバイト列などの形式に変換しネットワークやファイルに保存・転送する仕組みのこと
DataStoreではKotlin CoroutinesとFlowオブジェクトを活用することでデータを非同期的に一貫した形でトランザクションとして保存することができるようになっています。そのためKotlin Coroutinesの扱いには慣れておく必要があります。
また保存できる型は以下の通りです。
- int
- long
- float
- boolean
- String
- Set<String>
SharedPreferencesは非推奨?
似たようなものにSharedPreferencesがありますが、公式よりSharedPreferencesではなくDataStoreを使うことが推奨されています。現在SharedPreferencesを使用してデータを保存している場合は、DataStoreに移行することを検討するよう公式がアナウンスしているようです。
またローカルにデータを永続的に保存する別の方法としてRoomDataBase
もあります。
Preferences DataStoreとProto DataStore
DataStoreの中でも大きく分けて2種類に分かれます。
Preferences DataStore
Key-Value形式でデータの保存およびアクセスを行う。定義済みのスキーマは必要ないがタイプセーフではない
Proto DataStore
カスタムデータ型のインスタンスとしてデータを保存。プロトコルバッファを使用してスキーマを定義する必要があるがタイプセーフ
Preferences DataStoreの使い方
ではここからはDataStoreを使用する方法をまとめていきます。今回はPreferences DataStoreを使用していきます。
流れ
- 依存関係の追加
- Datastore<Preferences>のインスタンスを作成
- インスタンスに保存する必要がある各値のキーを定義
依存関係の追加
DataStoreを実装するためには依存関係を追加する必要があります。使用する種類によって追加するコードが変わります。
Preferences DataStore
Proto DataStore
※ 2025年5月現在の最新Verは1.1.5
ですがstringPreferencesKey
などほとんどがUnresolved reference
になってしまっていたので注意してください。
Datastore<Preferences>のインスタンスを作成
Datastoreを使用するにはまずDatastore<Preferences>インスタンスを作成する必要があります。これはkotlinファイルの最上位でインスタンス生成を1回呼び出し、定義したプロパティを介して他の下層のファイルからアクセスします。なので名前はなんでも良いですが例えば「DataStoreExtensions.kt」というファイル名を作り、以下のimport
文も含めてペーストしてください。name
にはアプリ内で使用するDatastoreの用途がわかるようなDB名をつけてください。またこのインスタンスはシングルトンになります。
ここで手打ちで入力するとAndroid Studioのバージョンによっては自動補完で異なるimport
文が記述され以下のようなエラーが発生(後半で紹介してます)してしまいます。
インスタンスに保存する必要がある各値のキーを定義
Preference DataStoreでは定義済みのスキーマを使用しないため、任意のキーを定義する関数を使用してDataStore<Preferences>インスタンスに保存する値のキーを定義する必要があります。キーを定義する関数はデータ型によって異なりInt
型ならintPreferencesKey
、String
型ならstringPreferenceKey
を使用します。
これでDataStoreを使う準備が整ったので実際にデータを保存、取得してみたいと思います。
データを保存する
ではこのまま「カウンターアプリ」を作っていきます。ここからは「MainActivity.kt」内に記述していきます。
データを保存するには生成したdataStore
インスタンスからedit
メソッドを呼び出します。引数からMutablePreference
型が取得できるので定義した名前の変数settings
を用意して受け取ります。あとはMutablePreference[キー]
形式で参照できるので新しい値を格納します。
また非同期処理で実行されることを想定してsuspend
関数(Coroutinesのコード)にしています。あとはボタンのクリックイベントなどから呼び出せばOKです。
保存されたデータは/data/app/パッケージ名/files/datastore
内に保管されます。
データを取得する
データを1回だけ取得したい場合はfirstOrNull
を使用します。dataStore.data
からDataStoreに保存されているデータにアクセスできるようになっています。その際に例外IOException
が発生する可能性があるのでcatch
で例外を捕捉しています。
Flowで取得して観測する
ローカルに保存しているデータの変更を観測するためにはFlow
オブジェクトで取得します。firstOrNull
を使用せずにmap
を使用して実際のデータを流れるようにすることでFlow<Int>
型で取得することができます。
またこの際にNo type arguments expected for class Flow
というエラーが発生することがありますが詳細はこちらをご覧ください。
あとはこれを元にデータを取得しUIに反映させる処理を実装してみます。
呼び出し時は以下のような感じです。
全体のコード
DataStoreを管理するクラスを作成してみる
ここまでの紹介では実際のアプリに組み込んだ際の汎用性が拡張性が全くないのでもう少し使いやすくしていきます。次は「カウンター」ではなくユーザー名を保存できるようにしていきます。dataStore
の定義は変わりませんが、キーの定義と保存・取得のロジックを保持するクラスに切り出してみました。
Activity側では以下のように書けるようになりました。
observeCurrentUser
でFlow<String?>
オブジェクトを受け取りcollect
メソッドで受け取った値に対しての処理を定義しています。
Property delegate must have a 'getValue(Context, KProperty<*>)' method. None of the following functions is suitable:public abstract operator fun getValue(thisRef: Context, property: KProperty<*>): DataStore<Preferences> defined in kotlin.properties.ReadOnlyProperty
上記のDataStoreのDatastore<Preferences>のインスタンスを作成するコードをファイルに記述して実行すると以下のようなエラーが発生することがあります。
これはimport
文が正しく読み込まれていないために発生しています。本来ならandroidx.datastore.preferences.core.Preferences
が正しいのですが自動補完でに任せるとjava.util.prefs.Preferences
が記述されてしまいます。
なのでjava.util.prefs.Preferences
をandroidx.datastore.preferences.core.Preferences
に入れ替えることでこのエラーは解決します。
No type arguments expected for class Flow
Flow<Int>
を記述した際に以下のようなエラーが発生することがあります。
これもimport
文が正しく読み込まれていないために発生するエラーです。なのでjava.util.concurrent.Flow
をkotlinx.coroutines.flow.Flow
に入れ替えることでこのエラーは解決します。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。