# [Introduction to DataStore - MAD Skills](https://youtube.com/watch?v=mdQjuZbLv9Y)

### DataStore 是什麼?


- Jetpack 推出的資料儲存庫,用於取代 SharedPreferences
- 支援 Kotlin Coroutine 和 Flow,實現非同步資料操作
- 適合儲存小型資料如使用者偏好或應用狀態
- 提供 Preferences DataStore 和 Proto DataStore 兩種實作
---
### SharedPreferences 的缺點




- 不是執行緒安全,可能導致資料不一致
- 同步操作可能阻塞 UI 執行緒,造成卡頓或 ANR
- 易因型別錯誤拋出例外(如 ClassCastException)
- 缺乏型別保護與資料結構定義
- 沒有內建的資料遷移機制
---
### DataStore 的優勢

- 完全非同步 API,避免 UI 被阻塞
- Flow 支援錯誤捕捉,提升穩定性
- Proto DataStore 支援資料結構定義與型別安全
- 提供原子性讀寫操作與強一致性
- 支援從 SharedPreferences 輕鬆遷移
---
### Preferences DataStore 與 Proto DataStore 的比較


- Preferences DataStore 使用 key-value 形式儲存資料
- Proto DataStore 使用 Protocol Buffers 定義結構與型別
- Preferences DataStore 適合快速遷移 SharedPreferences
- Proto DataStore 適合需要儲存複雜資料並保證型別安全的場景
---
### 何時使用 DataStore 或 Room?

- 大型資料、需要部分更新或資料關聯應選擇 Room
- 小型設定資料、偏好值或狀態資料適合使用 DataStore
---
### 後續內容預告
- 下一集將介紹如何使用 Proto DataStore 和 Preferences DataStore
- 包含資料讀寫、錯誤處理與 SharedPreferences 的遷移方法
# Preferences DataStore - MAD Skills

### Preferences DataStore 簡介


- 是 DataStore 的其中一種實作,使用 key-value 儲存資料
- 不需定義資料 schema,類似 SharedPreferences
- 提供非同步 API,依賴 Kotlin Coroutine 與 Flow
- 相較 SharedPreferences,不具完整型別安全
---
### 建立 Preferences DataStore


- 需加入 `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)

### Proto DataStore 概覽


- Proto 使用 Protocol Buffers 儲存結構化、具型別安全的小型資料集
- 相較 Preferences DataStore 不使用 key-value 結構
- 提供完整非同步 API,支援 Kotlin Coroutine 和 Flow
- 擁有資料遷移與例外處理機制,避免阻塞 UI 執行緒
---
### 使用 Protocol Buffers

- 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)

### 使用 Hilt 注入 DataStore

- 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)


### 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**:驗證遷移後資料是否正確儲存至磁碟。