# [Introduction to DataStore - MAD Skills](https://youtube.com/watch?v=mdQjuZbLv9Y) ![image](https://hackmd.io/_uploads/HkbLBzYTJx.png) ### DataStore 是什麼? ![image](https://hackmd.io/_uploads/Hy0W8zt6kl.png) ![image](https://hackmd.io/_uploads/SyRx8Mt6ke.png) - Jetpack 推出的資料儲存庫,用於取代 SharedPreferences - 支援 Kotlin Coroutine 和 Flow,實現非同步資料操作 - 適合儲存小型資料如使用者偏好或應用狀態 - 提供 Preferences DataStore 和 Proto DataStore 兩種實作 --- ### SharedPreferences 的缺點 ![image](https://hackmd.io/_uploads/rJLzLGKakl.png) ![image](https://hackmd.io/_uploads/ByuVLGtakl.png) ![image](https://hackmd.io/_uploads/S16IUztp1l.png) ![image](https://hackmd.io/_uploads/S1uu8fFp1l.png) - 不是執行緒安全,可能導致資料不一致 - 同步操作可能阻塞 UI 執行緒,造成卡頓或 ANR - 易因型別錯誤拋出例外(如 ClassCastException) - 缺乏型別保護與資料結構定義 - 沒有內建的資料遷移機制 --- ### DataStore 的優勢 ![image](https://hackmd.io/_uploads/HJTY8fYaye.png) - 完全非同步 API,避免 UI 被阻塞 - Flow 支援錯誤捕捉,提升穩定性 - Proto DataStore 支援資料結構定義與型別安全 - 提供原子性讀寫操作與強一致性 - 支援從 SharedPreferences 輕鬆遷移 --- ### Preferences DataStore 與 Proto DataStore 的比較 ![image](https://hackmd.io/_uploads/rJBc8MtT1x.png) ![image](https://hackmd.io/_uploads/SJQhLfYTke.png) - Preferences DataStore 使用 key-value 形式儲存資料 - Proto DataStore 使用 Protocol Buffers 定義結構與型別 - Preferences DataStore 適合快速遷移 SharedPreferences - Proto DataStore 適合需要儲存複雜資料並保證型別安全的場景 --- ### 何時使用 DataStore 或 Room? ![image](https://hackmd.io/_uploads/SJzRLftpkl.png) - 大型資料、需要部分更新或資料關聯應選擇 Room - 小型設定資料、偏好值或狀態資料適合使用 DataStore --- ### 後續內容預告 - 下一集將介紹如何使用 Proto DataStore 和 Preferences DataStore - 包含資料讀寫、錯誤處理與 SharedPreferences 的遷移方法 # Preferences DataStore - MAD Skills ![image](https://hackmd.io/_uploads/rJ8ZwMKpyg.png) ### Preferences DataStore 簡介 ![image](https://hackmd.io/_uploads/SkzC_Mt6kg.png) ![image](https://hackmd.io/_uploads/rkYVFGF61l.png) - 是 DataStore 的其中一種實作,使用 key-value 儲存資料 - 不需定義資料 schema,類似 SharedPreferences - 提供非同步 API,依賴 Kotlin Coroutine 與 Flow - 相較 SharedPreferences,不具完整型別安全 --- ### 建立 Preferences DataStore ![image](https://hackmd.io/_uploads/rkrHKzt61l.png) ![image](https://hackmd.io/_uploads/rJsvtft61g.png) - 需加入 `datastore-preferences` 相依套件 - 使用 Kotlin 的 extension delegate 建立 DataStore 實例 - 需傳入檔案名稱作為參數,通常綁定於 Context - 同一個檔案只能有一個 DataStore 實例,否則會導致錯誤 --- ### 建立 Preference Keys - 使用 `booleanPreferencesKey`、`stringPreferencesKey` 等函式建立 key - key 名稱需為唯一值,與 SharedPreferences 類似 - 雖有指定型別,但仍有風險,不具強制型別安全 --- ### 讀取資料 - 使用 `dataStore.data` 取得 Flow,隨資料變動即發出更新 - 可用 `map` 將 Preferences 轉換成自訂的資料模型 - 可使用 `first()` 取得當下 snapshot,不須訂閱 Flow - 不建議手動快取資料,會破壞 DataStore 的一致性保障 --- ### 寫入資料 - 使用 `dataStore.edit` 搭配 suspend block 修改資料 - 傳入的 `MutablePreferences` 可視為可修改的 map - 修改操作是原子性的讀取-修改-寫入流程 - 只在 transform 成功後才會實際寫入磁碟 - 禁止在 transform block 外修改 MutablePreferences,否則無效 --- ### 錯誤處理 - 讀取資料時可使用 Flow 的 `catch` 處理錯誤 - 通常補上空 Preferences 或備用值 - 寫入時可用 try-catch 捕捉錯誤,非預期錯誤應重新拋出 --- ### SharedPreferences 資料遷移 - 使用 `SharedPreferencesMigration` 輕鬆遷移舊資料 - 提供 Context、SharedPreferences 名稱與欲遷移的 key 集合 - 使用 `produceMigrations` 傳入遷移邏輯至 DataStore - 遷移會在 DataStore 初始化前執行,保證一致性 - 遷移後可移除 SharedPreferences 的使用 --- ### 總覽與預告 - 本集介紹 Preferences DataStore 的使用與錯誤處理 - 下集將介紹 Proto DataStore 的用法與更多進階功能 # [Proto DataStore - MAD Skills](https://youtube.com/watch?v=aYhgwII6_VM) ![image](https://hackmd.io/_uploads/B1uw9fK6ke.png) ### Proto DataStore 概覽 ![image](https://hackmd.io/_uploads/HkxjszKT1g.png) ![image](https://hackmd.io/_uploads/SkGAifYTJl.png) - Proto 使用 Protocol Buffers 儲存結構化、具型別安全的小型資料集 - 相較 Preferences DataStore 不使用 key-value 結構 - 提供完整非同步 API,支援 Kotlin Coroutine 和 Flow - 擁有資料遷移與例外處理機制,避免阻塞 UI 執行緒 --- ### 使用 Protocol Buffers ![image](https://hackmd.io/_uploads/rkc0izt6kg.png) - Protocol Buffers 是一種語言與平台無關的資料序列化格式 - 在 `proto` 檔中定義資料結構(message)與欄位類型 - 每個欄位需指定唯一編碼標籤(tag),不可變更 - 編譯後會自動產生對應語言的類別(如 `UserPreferences`) --- ### 建立 Proto Serializer - 透過實作 `Serializer<T>` 來定義資料的讀寫邏輯 - 覆寫 `defaultValue`、`readFrom` 與 `writeTo` 方法 - 可設定 `corruptionHandler` 來處理資料格式損毀的情況 - 建議只建立單一 DataStore 實例,避免功能異常 --- ### 建立 DataStore 實例 - 使用 `by dataStore` 建立,需傳入檔名與 serializer - 綁定於 Context(因為需要建立檔案) - 支援 `produceMigrations` 做資料遷移 - 可選擇加入 `corruptionHandler` 處理反序列化失敗的狀況 --- ### 讀取資料 - 使用 `dataStore.data` 提供 Flow,資料更新即發出 - 傳回值為已產生的類別(如 `UserPreferences`),不需手動轉換 - 可使用 `first()` 取得當下快照 - 不建議建立快取資料來源,會破壞一致性保證 --- ### 寫入資料 - 使用 `dataStore.updateData` 配合 suspend block 寫入 - 使用 `toBuilder()` 開啟物件進行修改 - 設定新值後使用 `build()` 完成轉換 - 資料寫入具原子性,更新成功後才會持久儲存 - 不可在 transform block 外修改資料,否則不會生效 --- ### SharedPreferences 資料遷移 - 使用 `SharedPreferencesMigration` 轉換舊資料 - 提供 context、名稱與轉換邏輯,轉為 Proto 類別 - 經由 `produceMigrations` 傳入 DataStore 建立 - 遷移只執行一次,完成後自動停止使用 SharedPreferences --- ### 錯誤處理 - 資料讀取錯誤會拋出 `IOException`,可透過 Flow 的 `catch` 處理 - 建議補上預設資料(如預設 instance)作為備案 - 寫入錯誤可用 try-catch 處理,遇非預期錯誤建議重新拋出 --- ### 後續內容預告 - 未來將探討如何將 DataStore 與 App 架構整合 - 包含使用 Hilt 進行依賴注入以及如何撰寫測試 # [DataStore: Best practices - MAD Skills](https://youtube.com/watch?v=S10ci36lBJ4) ![image](https://hackmd.io/_uploads/ryJECMKaJx.png) ### 使用 Hilt 注入 DataStore ![image](https://hackmd.io/_uploads/r12YAGKayx.png) - DataStore 應以單例方式使用,同一檔案只能建立一個實例 - 使用 Hilt 可簡化依賴注入流程 - 在 `Application` 類別加上 `@HiltAndroidApp` 啟用 Hilt - 建立 Hilt Module 並使用 `PreferencesDataStoreFactory` 建立 DataStore - 可設定 `corruptionHandler` 處理資料損壞、`migrations` 做資料遷移 - 使用 `@AndroidEntryPoint` 標記需要注入的 Activity 或 ViewModel - 使用 `@Inject` 標記建構子以注入 DataStore 實例 --- ### ProtoDataStore 注入方式 - 注入方式與 Preferences 類似 - 需額外提供 `UserPreferencesSerializer` - 可結合 `produceMigrations` 處理從 SharedPreferences 的遷移 --- ### Kotlin Data Class 與 Serialization - 可使用 Kotlin `data class` 配合 Serialization 取代 Protobuf - 需加上 `@Serializable` 標註類別 - 實作自定義 `Serializer` 並覆寫 `readFrom` 和 `writeTo` - 資料類別需完全不可變,所有屬性應使用 `val` - 避免使用 `var`、陣列或任何可變集合 - 建議使用 Kotlin Immutable Collections(如 `PersistentList`) - Parcelable 不適用於 DataStore,因版本間格式可能變動 --- ### Kotlin Serialization 優勢與注意事項 - 支援多種格式(如 JSON、Protobuf),範例中使用 JSON - 可利用 `copy()` 方法輕鬆更新資料 - 避免使用可變型別以免導致不一致與 Race Condition - 使用 Serialization 可減少樣板程式碼並提升可讀性 --- ### DataStore 的非同步特性 - 所有資料操作皆於 `Dispatchers.IO` 執行,避免 UI 阻塞 - 不提供同步 API,設計以避免 ANR 與卡頓 - Flow 提供即時資料更新,推薦配合使用 --- ### 在必要情境下進行同步操作 - 若必須同步取得資料,可使用 `runBlocking` - `runBlocking` 會阻塞執行緒,應慎用並避免在主執行緒使用 - 若無法避免,需確保錯誤處理、取消與 UI 回饋完善 - 建議透過非同步預載資料或重構程式碼來避免同步需求 --- ### 本集涵蓋主題 - 使用 Kotlin data class 與 Serialization 整合 DataStore - 在特殊需求下進行同步操作的方法與建議 - 透過 Hilt 將 DataStore 注入應用程式中各處使用 # [DataStore: Best practices (part 2) - MAD Skills](https://youtube.com/watch?v=ZqlZnSdSqI4) ![image](https://hackmd.io/_uploads/rJASkXt6Je.png) ![image](https://hackmd.io/_uploads/r1A7N7Fa1x.png) ### DataStore to DataStore 資料遷移 - 遷移可用於資料模型結構變動(如重新命名欄位、改變型別) - 實作 `DataMigration` 介面並覆寫 `shouldMigrate`、`migrate`、`cleanup` - `shouldMigrate` 控制是否執行遷移 - `migrate` 負責轉換資料,若失敗不會寫入磁碟 - `cleanup` 負責移除舊資料,僅在遷移成功後執行 - `produceMigrations` 接收一組遷移操作,於 DataStore 初始化前執行 - 可同時遷移多個舊 DataStore 實例 --- ### 建立 DataStore 遷移範例 - 從舊 Preferences DataStore 遷移至新 Preferences DataStore - 重新命名欄位並變更資料型別(如 float → int) - 其餘資料可直接轉移 - 所有邏輯可先實作在 Activity,再移至 Hilt Module 管理 --- ### 測試 DataStore 的方式 - 建議使用 Instrumentation Test 實際驗證讀寫行為 - 可選擇建立測試用 DataStore 或使用 Mock 方式注入 - 建議測試負責資料處理的 repository 層級 --- ### 測試環境建置 - 使用 `PreferencesDataStoreFactory` 建立測試用 DataStore 實例 - 使用測試專用檔案避免影響真實資料 - 使用 `TestCoroutineDispatcher` 與 `TestCoroutineScope` 控制 coroutine 執行 - 測試後需適當清除 coroutine job 與資料檔案 --- ### 撰寫測試案例 - 驗證 DataStore 初始資料狀態是否符合預期 - 測試 repository 初始化後是否正確設置預設資料 - 呼叫 suspend 函數時使用 `runBlockingTest` 包裹執行 - 測試是否成功寫入資料(如變更排序方式的欄位值) --- ### 擴充與維護測試 - 可依樣擴充更多測試案例以覆蓋不同功能 - 每次測試需初始化乾淨的測試環境 - 測試結束後應執行清理工作以確保下次執行無誤 --- ### 適用於 Proto DataStore - 同樣的遷移與測試模式也適用於 Proto DataStore - 差異僅在資料轉換的方式與使用的 Serializer 類別不同 # Resource * DataStore → https://goo.gle/33KWVP4 * Protocol Buffers → https://goo.gle/3FCLhTt * Save data in a local database using Room → https://goo.gle/3FFU0ED * Working with Preferences DataStore codelab → https://goo.gle/3AtpVXB * Working with Preferences DataStore GitHub → https://goo.gle/3fRREYz * Protocol buffers → https://goo.gle/3skAhFx * Kotlin DSL protobuf support → https://goo.gle/3J7vlur * Protobuf Plugin for Gradle → https://goo.gle/3GqoP0f * Working with Proto DataStore codelab → https://goo.gle/34ESXYL * Dependency injection with Hilt → https://goo.gle/3oySC0D * Using Hilt in your Android app codelab → https://goo.gle/3zB0OjI * Kotlin Serialization → https://goo.gle/3uwNo9n # Terminology - **Jetpack DataStore**:Google 推出的現代化資料儲存解決方案,用以取代 SharedPreferences。 - **SharedPreferences**:Android 傳統的鍵值對資料儲存工具,但存在執行緒安全與同步問題。 - **Kotlin Coroutines**:Kotlin 提供的協程功能,用於簡化非同步程式設計。 - **Kotlin Flow**:一種異步資料流工具,用於持續觀察資料變化。 - **Thread-Safe**:保證多執行緒環境下操作資料不會發生競爭或錯誤。 - **Non-blocking I/O**:非阻塞式輸入輸出操作,不會卡住 UI 執行緒。 - **Preferences DataStore**:使用鍵值對方式儲存資料的 DataStore 實作,不需定義資料結構。 - **Proto DataStore**:使用 ProtoBuf 以物件方式儲存資料,支援型別安全。 - **Protocol Buffers (ProtoBuf)**:Google 提出的序列化格式,用於高效儲存與傳輸資料。 - **Asynchronous API**:非同步應用程式介面,不阻塞主執行緒。 - **UI Thread**:主要用於更新與處理畫面的 Android 主執行緒。 - **ANR (Application Not Responding)**:應用程式無回應錯誤,通常因主執行緒被阻塞。 - **UI Jank**:畫面卡頓,常因 I/O 操作阻塞 UI 執行緒造成。 - **apply()**:SharedPreferences 的非同步儲存方法,但可能在 fsync 時阻塞。 - **commit()**:SharedPreferences 的同步儲存方法,可能導致主執行緒阻塞。 - **fsync**:將資料實際寫入磁碟的系統呼叫,通常是耗時操作。 - **ClassCastException**:型別轉換錯誤,常在 SharedPreferences 錯誤取值時發生。 - **Exception Handling**:處理執行期間例外狀況的技術。 - **Flow Error Signaling**:透過 Flow 傳遞錯誤訊息的機制。 - **Key-Value Pairs**:以鍵值對方式儲存資料的結構。 - **Type-Safety**:保證資料型別一致性,避免錯誤與崩潰。 - **Atomic Read-Modify-Write**:不可中斷的讀取-修改-寫入操作,確保資料一致性。 - **Transactional API**:支援交易機制的 API,可確保資料一致性與安全性。 - **Read-After-Write Consistency**:寫入後能馬上讀取到一致的資料狀態。 - **Migration**:將資料從舊儲存系統轉移到新系統的過程。 - **SharedPreferences Migration**:從 SharedPreferences 自動遷移資料至 DataStore。 - **Schema**:資料結構定義,在 Proto DataStore 中需預先定義。 - **Enums**:列舉型別,可於 Proto DataStore 中儲存。 - **Room**:Jetpack 中的資料庫框架,適合複雜與關聯型資料儲存。 - **Referential Integrity**:資料表間關聯完整性,用於資料庫系統如 Room。 - **Partial Updates**:僅更新資料部分欄位的功能,Room 支援但 DataStore 不支援。 - **Application State**:應用程式的狀態資料,例如登入狀態或使用者偏好。 - **Data Consistency**:資料一致性,Proto DataStore 透過交易與原子操作保證。 - **Data Serialization**:將物件轉換為可儲存或傳輸格式的過程。 - **Deserialization**:將儲存格式的資料還原為程式中可用的物件。 - **Coroutine Builders**:如 launch、async 等用於建立協程的函式。 - **Synchronous API**:同步介面,會阻塞呼叫執行緒。 - **Asynchronous Programming**:非同步程式設計,不阻塞主執行緒,提高效能。 - **Listener**:用於監聽資料變化的回呼介面。 - **Data Inconsistency**:資料不一致,SharedPreferences 常見問題之一。 - **Blocking Operations**:會造成執行緒等待的操作,應避免於 UI 執行緒執行。 - **Main Thread Violation**:在主執行緒執行耗時操作的錯誤行為。 - **I/O Operations**:資料讀寫操作,對效能有顯著影響。 - **Streaming API**:資料流 API,例如 Kotlin Flow 可持續發送資料。 - **Reactive Programming**:資料驅動的程式設計模型,UI 可隨資料自動更新。 - **Cold Flow**:未被收集前不會執行的 Flow。 - **DataStore Preferences Migration**:將 SharedPreferences 資料遷移至 Preferences DataStore。 - **DataStore Proto Migration**:將資料遷移至 Proto DataStore,包含 schema 建立與轉換。 - **Minimal API Changes**:少量修改即可從 SharedPreferences 遷移至 Preferences DataStore。 - **Complex Data Modeling**:使用 Proto DataStore 儲存結構化資料如物件、列表。 - **Schema Evolution**:ProtoBuf 支援資料結構演進,可擴充而不破壞既有資料。 - **Default Implementation**:預設實作,DataStore 提供 Preferences 與 Proto 兩種。 - **App Configuration**:應用程式設定,可儲存於 DataStore。 - **Event Listener on UI Thread**:SharedPreferences 的監聽器在主執行緒運作,可能造成卡頓。 - **Coroutines Scope**:定義協程的生命週期範圍,管理資源釋放。 - **File-based Storage**:DataStore 將資料儲存在裝置內的檔案中。 - **Error Propagation**:錯誤傳遞機制,Flow 可處理讀寫錯誤。 - **Typed Object Storage**:儲存具明確型別的物件,例如 Proto DataStore 支援的資料類型。 - **Preferences DataStore**:DataStore 的實作之一,使用鍵值對儲存資料,無需定義資料結構。 - **Key-Value Pairs**:以鍵與值組合的資料結構,用於儲存簡單型別的偏好設定。 - **Schema-less**:不需事先定義資料結構的儲存方式。 - **SharedPreferences**:舊有的資料儲存方式,已由 DataStore 取代。 - **Coroutine**:Kotlin 的非同步程式設計模型,用於背景處理。 - **Flow**:Kotlin 中表示資料流的類型,可持續觀察資料變化。 - **Dispatcher.IO**:協程排程器,適合執行 I/O 密集的任務。 - **Preferences**:抽象類別,表示 DataStore 中儲存的鍵值資料集合。 - **DataStore Preferences Interface**:提供 Preferences DataStore 存取功能的介面。 - **Preferences Flow**:透過 Flow 發出偏好設定資料的資料流。 - **PreferenceKey**:代表 Preferences DataStore 中某個鍵的型別。 - **BooleanPreferenceKey**:專門儲存布林值的偏好鍵。 - **Edit Function**:唯一可用來變更 Preferences DataStore 資料的 suspend 函式。 - **MutablePreferences**:可變版本的 Preferences,用於編輯資料。 - **Transform Block**:提供給 edit 函式用來更新資料的 suspend 區塊。 - **Atomic Operation**:確保資料一致性的不可中斷操作。 - **Transaction**:讀寫操作以交易方式進行,確保一致性。 - **State Snapshot**:偏好設定當下的單一快照。 - **first() Operator**:Flow 的操作子,用來取得首次發出的資料。 - **Exception Handling**:資料讀寫過程中錯誤處理的機制。 - **IOException**:讀寫資料時發生的輸入輸出例外狀況。 - **catch Operator**:Flow 中用於攔截並處理例外的操作子。 - **Empty Preferences**:例外發生時可使用的備援資料。 - **try-catch Block**:Kotlin 中處理例外的結構。 - **rethrow Exception**:重新拋出非 I/O 類別的例外。 - **produceMigrations**:用於設定資料遷移的參數。 - **SharedPreferencesMigration**:將 SharedPreferences 的資料遷移至 DataStore。 - **getMigration Function**:取得 SharedPreferences 中資料並轉移至 DataStore 的函式。 - **Singleton**:單一實例模式,避免多個 DataStore 實例導致衝突。 - **Extension Property**:擴充屬性,用於將 DataStore 建立為 context 的屬性。 - **Context**:Android 應用的上下文,常用於存取資源與建立元件。 - **File Object**:實際儲存 Preferences 資料的檔案實體。 - **Activity-Level Initialization**:在 Activity 頂層建立 DataStore 實例的方式。 - **Dependency Injection (DI)**:將元件注入而非手動建立的設計模式。 - **Enum**:列舉類型,可儲存為值的一部分(如排序選項)。 - **SortOrder Enum**:排序的列舉定義,如依截止日或優先順序。 - **CodeLab**:官方提供的實作練習教材。 - **Data Consistency**:保證資料在所有操作後保持一致。 - **Uncaught Exception**:未捕捉的例外,可能導致應用程式崩潰。 - **Type Safety**:型別安全機制,減少資料錯誤或型別轉換問題。 - **Data Model**:資料的結構或定義,在 Preferences 中以鍵值對表示。 - **CoroutineScope**:協程的生命週期控制範圍。 - **UI Thread Blocking**:在主執行緒中執行耗時操作導致卡頓。 - **Hands-on Implementation**:實作導向的學習方式,如 CodeLab 提供的範例。 - **Filter Preferences**:使用者偏好中篩選相關的設定。 - **Persistent Storage**:將資料持久儲存在裝置中。 - **Live Update**:當資料更新時,介面自動反映變化。 - **Default Argument**:Kotlin 中函式預設的參數值。 - **DataStore Delegate**:委託屬性用於簡化 DataStore 建立流程。 - **Task Repository**:管理任務資料與偏好設定的資料來源類別。 - **DataStore Migration Safety**:資料轉移過程中的資料安全保證。 - **Backup Data**:在讀取失敗時回傳的預設備援資料。 - **Manual Mutation**:手動修改資料物件,應避免於 transform 區塊外執行。 - **Suspend Lambda**:可掛起執行的匿名函式,用於協程中。 - **Exception Propagation**:例外錯誤的傳遞與處理流程。 - **State Management**:管理資料狀態與變化的架構設計。 - **Asynchronous Storage**:非同步資料儲存操作,避免卡頓。 - **Migration Trigger**:在資料被使用前自動觸發遷移的機制。 - **Immutable Preferences**:一旦建立後不可修改的偏好資料集合。 - **Proto DataStore**:Jetpack DataStore 的一種實作,使用 Protocol Buffers 儲存類型化資料並提供型別安全。 - **Protocol Buffers (ProtoBuf)**:Google 提供的結構化資料序列化格式,具備高效能與可擴展性。 - **Typed Objects**:具備明確型別定義的資料物件,在 Proto DataStore 中為儲存單位。 - **Key-Value Pair**:鍵值對格式,與 Proto 相比為結構較簡單的儲存方式。 - **Asynchronous API**:非同步應用程式介面,透過協程避免阻塞主執行緒。 - **Flow**:Kotlin 提供的資料流工具,用於觀察與處理資料變化。 - **Error Signaling Mechanism**:透過 Flow 傳遞錯誤的機制,可捕捉並處理例外狀況。 - **Kotlin Coroutine**:Kotlin 的非同步工具,簡化並行與背景作業。 - **Data Migration**:將資料從其他來源(如 SharedPreferences)轉移至 DataStore 的過程。 - **Proto Schema**:使用 `.proto` 檔定義的資料結構,用作序列化依據。 - **Proto File**:包含訊息定義的 `.proto` 格式檔案,用於生成資料模型。 - **Message**:ProtoBuf 的資料單位,代表一個資料物件的型別與欄位。 - **Field Tag**:Proto 中欄位的唯一標識符,用於編碼與解碼資料。 - **Proto Directory**:放置 `.proto` 檔案的專案資料夾。 - **Kotlin DSL for Proto**:使用 Kotlin 語法定義 ProtoBuf 結構的方式,提升可讀性與一致性。 - **DataStore Serializer**:負責將資料物件與 Proto 格式互轉的元件。 - **defaultValue**:當資料不存在時所回傳的預設值。 - **writeTo**:將記憶體中的物件轉換成儲存格式並寫入檔案的方法。 - **readFrom**:將檔案中的資料轉換為記憶體中物件的方法。 - **CorruptionHandler**:在資料毀損時回應的處理器,可提供備援資料。 - **CorruptionException**:當資料無法正確還原為物件時拋出的例外。 - **DataStore Interface**:主要的存取接口,提供讀寫與觀察 Proto 資料的能力。 - **Delegate DataStore**:透過屬性委託的方式建立 DataStore 實例。 - **Context Receiver**:用於建立 DataStore 的 Android `Context` 類型接收器。 - **ProduceMigrations**:提供遷移邏輯的參數,定義如何將舊資料轉為新格式。 - **UserPreferences**:由 Proto 編譯器自動生成的資料類別。 - **SharedPreferences Migration**:將 SharedPreferences 的資料轉移至 Proto DataStore 的過程。 - **Migration Block**:在遷移時定義轉換邏輯的區塊。 - **Generated Class**:由 `.proto` 檔編譯生成的類別,例如 UserPreferences。 - **first() Operator**:Kotlin Flow 的操作子,用於取得首個值而不訂閱變化。 - **Transform Block**:在 updateData 中指定變更邏輯的協程區塊。 - **updateData()**:唯一用於更新 Proto DataStore 的 API。 - **toBuilder()**:取得可變版本的 Proto 物件,用以進行資料修改。 - **build()**:完成資料更新後,將可變物件轉回不可變的 Proto 類型。 - **Atomic Read-Modify-Write**:不可中斷的資料操作流程,確保一致性與正確性。 - **Disk Persistence**:將資料安全儲存至磁碟的機制。 - **Singleton**:單一實例設計模式,用以防止多個 DataStore 實例造成資料不一致。 - **Catch Operator**:用於處理 Flow 中例外的操作子。 - **Backup Data**:當發生錯誤時回傳的預設或備援資料。 - **Try-Catch Block**:Kotlin 用來捕捉與處理錯誤的程式結構。 - **Rethrow Exception**:對非預期例外進行重新拋出處理的建議行為。 - **Build Proto Directory**:存放編譯後 `.proto` 檔產生類別的資料夾。 - **Code Generation**:透過工具根據 `.proto` 檔案自動生成程式碼的機制。 - **Java Lite**:精簡版 Proto 編譯器產生的 Java 類別,用於 Android 開發。 - **Task Repository**:應用程式中管理任務資料與設定的資料層。 - **UI Thread Unblocking**:確保 UI 執行緒不被耗時的 I/O 操作阻塞。 - **No Manual Mapping**:Proto 不需手動將儲存資料轉換為資料類別。 - **Consistency Guarantee**:Proto 保證每次資料操作具一致性與準確性。 - **One-Time Migration**:資料僅在首次遷移時轉移並移除 SharedPreferences 中對應鍵。 - **Dispatchers.IO**:Kotlin 的背景執行緒調度器,適用於 I/O 操作。 - **Immutable Data**:資料儲存後不可被任意更改,需透過 builder 重新建立。 - **Nested Message Type**:在 Proto 中作為欄位型別的另一個訊息類型,例如排序順序。 - **SortOrder Enum**:代表任務排序方式的列舉型態,可用於 Proto 欄位。 - **Task Filter Preferences**:使用者選擇的任務篩選條件資料。 - **Proto Compilation**:將 `.proto` 檔轉為目標語言類別的編譯過程。 - **Preference Replacement**:使用 Proto DataStore 取代傳統 SharedPreferences 的實務方式。 - **DataStore to DataStore Migration**:將資料從一個 DataStore 實例遷移至另一個的過程,常用於資料結構變更。 - **DataMigration Interface**:Jetpack DataStore 中定義資料遷移邏輯的介面。 - **shouldMigrate()**:DataMigration 方法之一,用於判斷是否需要進行遷移。 - **migrate()**:DataMigration 方法,用來執行實際的資料轉換與遷移。 - **cleanup()**:遷移成功後用來清除舊資料來源的方法。 - **Preferences DataStore Delegate**:透過委託方式建立 Preferences DataStore 實例。 - **produceMigrations**:DataStore 建立時提供遷移邏輯的參數。 - **Old DataStore**:資料遷移前的原始 DataStore 實例。 - **New DataStore**:資料遷移後的目標 DataStore 實例。 - **Instrumentation Testing**:使用實體裝置或模擬器進行的整合測試。 - **Mocking**:建立模擬物件以取代實際依賴進行單元測試。 - **UserPreferencesRepository**:封裝與 DataStore 互動邏輯的類別。 - **Test Class**:定義測試邏輯的類別,通常以功能單位為對象。 - **Test Subject**:被測試的主要物件或類別。 - **Test Coroutine Dispatcher**:專用於測試的 Kotlin 協程排程器。 - **Test Coroutine Scope**:提供控制協程執行與取消的測試範圍。 - **runBlockingTest**:用於在測試中執行 suspend 函式的函式。 - **Snapshot**:資料的即時快照,用於在特定時間點取得資料狀態。 - **Default Instance**:當 DataStore 無資料時提供的預設資料物件。 - **Suspend Function**:Kotlin 中可被暫停執行的函式,需在協程中使用。 - **Coroutine-based Testing**:針對使用協程程式碼所設計的測試流程。 - **enableSortByDeadline()**:修改偏好設定的函式範例。 - **Flow Testing**:對 Kotlin Flow 所進行的測試,確認資料流正確發出。 - **Expected Result**:測試中預期出現的資料或狀態。 - **Actual Result**:測試執行時實際得到的資料或狀態。 - **Test Context**:測試執行時所使用的 Context,可建立測試專用資源。 - **File-based Testing**:在實際檔案上進行讀寫操作的測試方式。 - **Data Verification**:驗證資料是否正確更新至 DataStore 的流程。 - **Unit Testing**:針對程式最小單元(函式或類別)進行的測試。 - **Integration Testing**:測試多個元件之間的整合與互動。 - **Preferences DataStore Factory**:用來建立 Preferences DataStore 實例的工廠方法。 - **Job Cancellation**:測試結束時取消協程工作的操作,避免資源外洩。 - **Test Cleanup**:測試結束後的清理流程,如刪除檔案或取消任務。 - **Repository Function Testing**:對資料存取層功能的測試。 - **Proto to Proto Migration**:從一個 Proto DataStore 遷移至另一個 Proto DataStore 的流程。 - **Type Transformation**:在遷移過程中變更資料欄位型別的操作。 - **Key Remapping**:將舊的鍵值對對應到新的鍵名稱。 - **Exception Propagation**:例外在程式中向上傳遞並處理的流程。 - **Test File Creation**:建立專屬於測試的資料檔案。 - **Hilt Injection**:使用 Hilt 對依賴進行注入的方式。 - **Data Validation**:測試中用於驗證資料正確性的步驟。 - **Custom Migration Logic**:根據特定條件與需求所實作的資料遷移邏輯。 - **Preferences Key Migration**:針對 Preferences 中特定鍵值進行遷移。 - **Migration Trigger**:觸發遷移的條件與流程。 - **Temporary DataStore**:測試期間使用的暫時性 DataStore 實例。 - **Test Scope Isolation**:將每個測試案例隔離以避免資料互相干擾。 - **Flow Emission Assertion**:檢查 Flow 是否發出正確資料的測試。 - **Delay-Free Execution**:測試中立即執行所有排程任務的機制。 - **Migration Retry Mechanism**:當遷移失敗時自動重試的內建邏輯。 - **Test Coverage**:測試涵蓋的程式範圍與比例。 - **Manual Cleanup Fallback**:當自動 cleanup 失敗時的手動補救策略。 - **DataStore Initialization Timing**:DataStore 初始化階段進行遷移與設置。 - **Persistent Data Validation**:驗證遷移後資料是否正確儲存至磁碟。