Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
DataStoreを導入してみた
Search
kobaken
April 20, 2023
Technology
400
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
DataStoreを導入してみた
kobaken
April 20, 2023
More Decks by kobaken
See All by kobaken
AIがレビューする時代に、 Androidエンジニアは何をレビューするのか 〜 土台づくりとレビュー再設計 〜
kobaken0029
3
720
In the Age of AI Code Review, What Should Android Engineers Review? - Building the Foundation & Redesigning Code Review -
kobaken0029
0
32
複数行のTextで中間省略(…)を実現する
kobaken0029
0
87
Jetpack Compose Preview実践ガイド
kobaken0029
0
170
Serializable / Parcelableとの上手な付き合い方
kobaken0029
0
230
Kotlinの好きなところ
kobaken0029
0
1.4k
Compose駆動開発のためのマルチモジュール化
kobaken0029
0
280
Epoxyを用いたレイアウト構築術
kobaken0029
1
270
Androidエンジニアが1週間でiOSアプリ開発を学び、1ヶ月で大規模アプリ開発にJOINした話
kobaken0029
0
3.9k
Other Decks in Technology
See All in Technology
幾何アルゴリズムで なめらかなピン操作を / iOSDC Japan 2026 / smoothpin
kazumanagano
0
230
AI-DLCって実際どう? 〜聞きたいこと全部聞いてみる〜
news_it_enj
0
250
全員がプロダクトへ向き合う組織を持続成長させるために——組織づくりのフライホイールと4象限 / The Flywheel Model and Four Quadrants for Organizational Design
hiro_torii
4
940
Bet AI Day 2026丨Production-Ready AI Agents — エンタープライズの実務を任せるための設計と運用
layerx
PRO
4
2.7k
Screen Lens - 今見てる画面を翻訳する
komagata
0
180
ASTを使って影響範囲を特定する
nealle
0
130
When Does a Local Qwen Start to Break
morshoto
0
190
Multica × 長期記憶:40個のミニプロジェクト管理
eiei114
1
220
DEFCON_CHV_CTF_Write-up.pdf
bata_24
0
110
AI時代におけるプロダクト横断勉強会の設計
zozotech
PRO
0
170
日経電子版を支えていく Kasane Design System/fec_fukuoka
nikkei_engineer_recruiting
0
320
Bet AI Day 2026丨Agentは、「金融」という巨大産業の何を変えられるのか
layerx
PRO
0
1.2k
Featured
See All Featured
First, design no harm
axbom
PRO
2
1.3k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
Six Lessons from altMBA
skipperchong
29
4.5k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
930
Typedesign – Prime Four
hannesfritz
42
3.2k
KATA
mclloyd
PRO
35
15k
Chasing Engaging Ingredients in Design
codingconduct
0
300
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
6.2k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
340
Game over? The fight for quality and originality in the time of robots
wayneb77
1
270
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Transcript
@kobaken DataStoreΛಋೖͯ͠Έͨ
ࣗݾհ • kobakenʢ@koba_dog_ʣ • pixivࣄۀຊ෦ϚϯΨ෦ • AndroidΞϓϦΛͭͬͯ͘·͢ • ࠷ۙϙέΧͱϫϯϐʔεΧʔυ͕͍ʂ
ͱ͜ΖͰΈͳ͞Μ
pixivίϛοΫͬͯ͝ଘͰ͔͢ʁ
ίϛοΫΛઆ໌Ͱ͖Δ ͳΜ͔͍͍ײ͡ͷը૾
ΈͯͶʂ https://inside.pixiv.blog/2023/01/25/120000
ؓٳ
DataStoreͱ
DataStoreͱ • σʔλΛϩʔΧϧʹӬଓԽͰ͖ΔσʔλετϨʔδιϦϡʔγϣϯ • Android Jetpackʹؚ·Ε͍ͯΔϥΠϒϥϦ • 20209݄ʹ1.0.0-alpha1͕ެ։͞Εͨ • ݱࡏ҆ఆ൛ͱͯ͠1.0.0͕ϦϦʔε͞Ε͍ͯΔ
DataStoreͷಛ • Kotlin CoroutinesʹରԠ͍ͯ͠Δ • খنͰ୯७ͳσʔληοτʹద͍ͯ͠Δ • Preferences DataStoreͱProto DataStoreͷ2छྨ͕ଘࡏ͍ͯ͠Δ
• SharedPreferences͔ΒͷҠߦ͕Մೳ
Kotlin CoroutinesʹରԠ͍ͯ͠Δ • σʔλͷऔಘʹ fl ow • σʔλͷอଘʹsuspend
CoroutinesରԠ͞Ε͍ͯΔ༷ࢠ public interface DataStore<T> { public val data: Flow<T> public
suspend fun updateData(transform: suspend (t: T) -> T): T }
খنͰ୯७ͳσʔληοτʹ࠷దԽ • ୯७ͳσʔλͷΈΛӬଓԽ͢Δ͜ͱ • ෦ߋ৽ࢀর߹ੑΛαϙʔτ͍ͯ͠ͳ͍ • େنɾෳࡶͳσʔληοτ෦ߋ৽ɺࢀর߹ੑΛαϙʔτ͍ͨ͠ ߹RoomΛ͍·͠ΐ͏
2छྨͷDataStore • Key-ValueϖΞΛѻ͏Preferences DataStore • SharedPreferencesͷସ • ܕ͖ΦϒδΣΫτΛѻ͏Proto DataStore •
Protocol bufferΛ༻ͯ͠εΩʔϚఆٛΛ͢Δ • ܕ҆શ
SharedPreferences
SharedPreferences vs DataStore https://medium.com/androiddevelopers/introduction-to-jetpack-datastore-3dc8d74139e7
SharedPreferences͔ΒҠߦ͢ΔϝϦοτ • ඇಉظAPI͕αϙʔτ͞Ε͍ͯΔͨΊɺUIϒϩοΩϯάʹΑΔδϟϯΫ ANRͷൃੜϦεΫ͕ܰݮ͢Δ • σʔλͷҰ؏ੑɾ߹ੑ͕औΕ͍ͯΔ • ϚΠάϨʔγϣϯʹରԠ͍ͯ͠Δ
Google→։ൃऀ • ʮSharedPreferencesΛ༻ͯ͠σʔλΛอଘ͍ͯ͠Δ߹ɺ DataStoreʹҠߦ͢Δ͜ͱΛݕ౼͍ͯͩ͘͠͞ɻʯ https://developer.android.com/topic/libraries/architecture/datastore
ಋೖͯ͠ΈΔ
Preferences DataStore
ґଘؔͷՃ dependencies { implementation "androidx.datastore:datastore-preferences:1.0.0" }
Preferences DataStoreΛ࡞ val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = “settings")
Preferences DataStoreΛ࡞ val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = “settings") ⚠1ϑΝΠϧʹରͯ͠DataStoreͷΠϯελϯεγϯάϧτϯʹ͢Δ͜ͱ⚠
→ಉϓϩηε্ʹॴఆϑΝΠϧʹରͯ͠ΞΫςΟϒͳDataStore͕ෳ͋Δͱ σʔλʹ৮ΕΔࡍʹIllegalStateExceptionΛεϩʔ͢Δ
Preferences DataStoreΛ࡞ val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = “settings")
DataStoreͷinterfaceʢ࠶ܝʣ public interface DataStore<T> { public val data: Flow<T> public
suspend fun updateData(transform: suspend (t: T) -> T): T }
ಡΈऔΓ val COMIC_USER_IDS = stringSetPreferencesKey("comic_user_ids") val comicUserIdsFlow: Flow<Set<String>> = context.dataStore.data
.map { preferences -> preferences[COMIC_USER_ID] ?: emptySet() }
ಡΈऔΓ val COMIC_USER_IDS = stringSetPreferencesKey("comic_user_ids") val comicUserIdsFlow: Flow<Set<String>> = context.dataStore.data
.map { preferences -> preferences[COMIC_USER_ID] ?: emptySet() } booleanPreferencesKey intPreferencesKey longPreferencesKey fl oatPreferencesKey stringPreferencesKey
ॻ͖ࠐΈ val COMIC_USER_IDS = stringSetPreferencesKey("comic_user_ids") context.dataStore.edit { preferences -> preferences[COMIC_USER_IDS]
= newUserIds }
SharedPreferences→DataStoreͷҠߦ const val PREFERENCES_NAME = "..." val Context.dataStore by preferencesDataStore(
name = PREFERENCES_NAME, produceMigrations = { context -> SharedPreferencesMigration( context = context, sharedPreferencesName = PREFERENCES_NAME, // ࢦఆͨ͠keyͷΈҠߦͰ͖ΔʂʢσϑΥϧτҾMIGRATE_ALL_KEYSʣ keysToMigrate = setOf(Key.COMIC_USER_IDS) ) } )
SharedPreferences→DataStoreͷҠߦ const val PREFERENCES_NAME = "..." val Context.dataStore by preferencesDataStore(
name = PREFERENCES_NAME, produceMigrations = { context -> SharedPreferencesMigration( context = context, sharedPreferencesName = PREFERENCES_NAME, // ࢦఆͨ͠keyͷΈҠߦͰ͖ΔʂʢσϑΥϧτҾMIGRATE_ALL_KEYSʣ keysToMigrate = setOf(Key.COMIC_USER_IDS) ) } )
pixivίϛοΫͰͷӡ༻ํ๏
pixivίϛοΫͰͷํ • ৽ن࣮ͰੵۃతʹPreferences DataStoreΛ࠾༻͢Δ • طଘͷSharedPreferencesख͕ۭ͍ͨͱ͖ʹҠߦΛݕ౼ • 1िؒͷ10%Λ෦্࣭ʹࣗ༝ʹͯΒΕΔʢ10%ϧʔϧʣ
pixivίϛοΫͰͷӡ༻ • Preferences DataStoreΛѻ͏interfaceΛఆٛ • ӬଓԽ͍ͨ͠σʔλ͕͋ΕͦͷinterfaceΛܧঝ࣮ͯ͢͠Δ
DataStoreͷΠϯελϯεΛऔಘͰ͖ΔΑ͏ʹ͢Δ private const val PREFERENCES_NAME = "......" val Context.dataStore by
preferencesDataStore( name = PREFERENCES_NAME )
γϯάϧτϯͳDataStoreΛѻ͑ΔinterfaceΛఆٛ interface Preference { val context: Context val dataStore: DataStore<Preferences>
get() = context.dataStore }
ѻ͏σʔλʹԠͯ͡DataStoreͷ࣮Λ͢Δ interface ComicUserIdsPreference : Preference<Set<String>> { val userIds: Flow<Set<String>> suspend
fun add(id: String) suspend fun remove(id: String) }
ѻ͏σʔλʹ Ԡͯ͡DataStore ͷ࣮Λॻ͘ class ComicUserIdsPreferenceImpl @Inject( override val context: Context
) : ComicUserIdsPreference { override val userIds: Flow<Set<String>> get() = dataStore.data .catch { if (exception is IOException) { emit(emptyPreferences()) } else { throw exception } } .map { it[PreferencesKeys.ComicUserIds.key] ?: emptySet() } override suspend fun add(id: String) { dataStore.edit { it[PreferencesKeys.ComicUserIds.key] = it[PreferencesKeys.ComicUserIds.key].plus(id).toSet() } } override suspend fun remove(id: String) { dataStore.edit { it[PreferencesKeys.ComicUserIds.key] = it[PreferencesKeys.ComicUserIds.key].minus(id).toSet() } } } Dagger2ͰDIͯ͠·͢ ʢhilitҠߦ͍ͨ͠……ʣ
KeyΛཧ͢Δ sealed class PreferencesKeys<T>(val key: Preferences.Key<T>) { object ComicUserIds :
PreferencesKeys<Set<String>>(stringSetPreferencesKey("comic_user_ids")) ... } class PreferenceTest { @Test fun checkDuplicatedKeys() { val subClasses = PreferencesKeys::class.sealedSubclasses val nonDuplicatedKeys = subClasses.map { it.objectInstance?.key?.name }.toSet() Truth.assertThat(nonDuplicatedKeys.count()).isEqualTo(subClasses.count()) } } KeyͷॏෳΛ͙ͨΊʹsealed classͰఆٛ ॏෳνΣοΫͷςετ͔ͬ͠Γ࣮ࢪ
ಉظͰΛऔಘͨ͘͠ͳͬͨέʔε
ΞϓϦىಈ࣌ͷςʔϚө
ઃఆ͕ө͞ΕΔલʹભҠͯ͠͠·͍ ҙਤ͠ͳ͍ςʔϚ͕ͪΒ͍ͭͯ͠·͏
Կ͕ى͍ͬͯ͜Δͷ͔ • ΞϓϦىಈ࣌ʹApplicationΫϥεͰςʔϚઃఆΛऔಘͯ͠ద༻͍ͯ͠Δ • ςʔϚઃఆPreferences DataStoreͰӬଓԽ͍ͯ͠Δ • DataStoreಉظॲཧʹରԠ͍ͯ͠ͳ͍ • ΞϓϦىಈˠϗʔϜը໘ͷը໘ભҠʹςʔϚͷө͕ؒʹ߹Θͣɺσ
ϑΥϧτͷςʔϚ͕ө͞ΕΔ • ͦͷޙɺඇಉظʹө͞ΕͨςʔϚઃఆ͕ద༻͞Εͨ
Կ͕ى͍ͬͯ͜Δͷ͔ • ΞϓϦىಈ࣌ʹApplicationΫϥεͰςʔϚઃఆΛऔಘͯ͠ద༻͍ͯ͠Δ • ςʔϚઃఆPreferences DataStoreͰӬଓԽ͍ͯ͠Δ • DataStoreಉظॲཧʹରԠ͍ͯ͠ͳ͍ • ΞϓϦىಈˠϗʔϜը໘ͷը໘ભҠʹςʔϚͷө͕ؒʹ߹Θͣɺσ
ϑΥϧτͷςʔϚ͕ө͞ΕΔ • ͦͷޙɺඇಉظʹө͞ΕͨςʔϚઃఆ͕ద༻͞Εͨ
ղܾࡦ • DataStore͔ΒΛऔಘ͢ΔͷΛಉظॲཧʹ͢Δ • runBlockingͱFlow# fi rstΛۦ͢Δ • SharedPreferencesΛ͏
DataStoreͰಉظॲཧ͢Δ // ςʔϚͷద༻͕ྃ͢ΔͷΛͭͨΊʹrunBlockingͰॲཧ͢Δ runBlocking { initTheme() } private suspend fun
initTheme() { themeSettingPreference.currentThemeStatus.first().let { AppCompatDelegate.setDefaultNightMode( it.getAppTheme().convertNightModeParameter() ) } }
runBlocking͢Δͱ͖ͷҙࣄ߲ • લఏͱͯ͠ਪ͞ΕΔํ๏Ͱͳ͍ • ຖճϑΝΠϧͷI/O͕Δͱ͍͏Θ͚Ͱͳ͍ͷͰɺͦΕΛཧղͯ͠ར༻͢ΔͷΞϦ • UIεϨουΛϒϩοΩϯά͢ΔͷͰɺδϟϯΫANRͷՄೳੑ͋Δ • ैདྷͷSharedPreferencesͱಉ͡ •
ෳՕॴͰݺͼग़͢߹ࣄલʹϓϦϩʔυΛ͓ͯ͘͠ͷ͕ྑ͍ • 2ճҎ߱ͷݺͼग़͠ͰϝϞϦΩϟογϡʹώοτ͢Δ • Activity#onCreateͱ͔ͰݺͿͱΑ͍
·ͱΊ
·ͱΊ • DataStoreͱ৽͍͠ϩʔΧϧετϨʔδιϦϡʔγϣϯͰ͋Δ • Kotlin Coroutines/FlowʹରԠ͍ͯ͠Δ • SharedPreferences͔ΒͷϚΠάϨʔγϣϯՄೳ • ಉظॲཧ͕ඞཁʹͳͬͨΒrunBlocking͢Δ
͋Γ͕ͱ͏͍͟͝·ͨ͠🙇
ࢀߟจݙ • ެࣜυΩϡϝϯτΨΠυ • Introduction to Jetpack DataStore • ϓϩμΫτͰ҆શʹDataStoreҠߦ͢Δ
• SharedPreferencesɺDataStoreҠߦͯ͠ΈΑ͏