🗡️
Jetpack DataStore(PreferencesDataStore)をHiltで注入する
一般的な記述法
Jetpack DataStoreはKotlinの言語仕様を生かした記述で簡単に定義できるようになっています。
// トップレベルに記述する必要がある
val Context.dataStore: DataStore<Preferences> by preferencesDataStore("settings")
トップレベル宣言をすると、パッケージをimportするだけで定義した内容へアクセスすることができます。
さらにContext
の拡張プロパティとして、委譲プロパティを使って定義しています。
拡張メソッドと比較すると拡張プロパティを頻繁に使う印象がないのですけれど、このように定義することでContext
を継承したActivity
などに、dataStore
プロパティが拡張されるため便利に使うことができます。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val value: Flow<String> = dataStore
.data
.map { preferences ->
preferences[stringPreferencesKey("foo")] ?: ""
}
}
by preferencesDataStore("settings")
の委譲プロパティを使うことで、DataStore
の生成処理などが隠蔽されます。ただのプロパティアクセスでDataStoreが生成され、使えるようになっています。
DIをしたい場合
こうしたKotlinの仕組みを利用した記述は、利便性は高いもののHiltでDataStoreインスタンスを管理して、注入したい場合には少し厄介です。
Context
の拡張プロパティになってしまうのでContext
があればどこでもDataStoreが取得できてしまいます。また、context.dataStore
を取得するためだけに、やれることの多いContext
をDIするのも避けたいところです。
この場合は、PreferenceDataStoreFactory
を使ってこのように書くとよさそうです。
@Singleton
@Provides
fun providePreferencesDataStore(
@ApplicationContext context: Context
): DataStore<Preferences> = PreferenceDataStoreFactory.create(
produceFile = {
context.preferencesDataStoreFile("settings")
}
)
やっていることは、実はby preferencesDataStore()
に委譲している初期生成の内容そのままですが、内部でDataStoreインスタンスをSingletonとして扱う部分を、Hiltの@Singleton
アノテーションに任せて簡潔にしています。
Discussion