應(yīng)用數(shù)據(jù)持久化概述
應(yīng)用數(shù)據(jù)持久化,是指應(yīng)用將內(nèi)存中的數(shù)據(jù)通過文件或數(shù)據(jù)庫(kù)的形式保存到設(shè)備上。內(nèi)存中的數(shù)據(jù)形態(tài)通常是任意的數(shù)據(jù)結(jié)構(gòu)或數(shù)據(jù)對(duì)象,存儲(chǔ)介質(zhì)上的數(shù)據(jù)形態(tài)可能是文本、數(shù)據(jù)庫(kù)、二進(jìn)制文件等。
OpenHarmony標(biāo)準(zhǔn)系統(tǒng)支持典型的存儲(chǔ)數(shù)據(jù)形態(tài),包括用戶首選項(xiàng)、鍵值型數(shù)據(jù)庫(kù)、關(guān)系型數(shù)據(jù)庫(kù)。
開發(fā)者可以根據(jù)如下功能介紹,選擇合適的數(shù)據(jù)形態(tài)以滿足自己應(yīng)用數(shù)據(jù)的持久化需要。
用戶首選項(xiàng)(Preferences):通常用于保存應(yīng)用的配置信息。數(shù)據(jù)通過文本的形式保存在設(shè)備中,應(yīng)用使用過程中會(huì)將文本中的數(shù)據(jù)全量加載到內(nèi)存中,所以訪問速度快、效率高,但不適合需要存儲(chǔ)大量數(shù)據(jù)的場(chǎng)景。
鍵值型數(shù)據(jù)庫(kù)(KV-Store):一種非關(guān)系型數(shù)據(jù)庫(kù),其數(shù)據(jù)以“鍵值”對(duì)的形式進(jìn)行組織、索引和存儲(chǔ),其中“鍵”作為唯一標(biāo)識(shí)符。適合很少數(shù)據(jù)關(guān)系和業(yè)務(wù)關(guān)系的業(yè)務(wù)數(shù)據(jù)存儲(chǔ),同時(shí)因其在分布式場(chǎng)景中降低了解決數(shù)據(jù)庫(kù)版本兼容問題的復(fù)雜度,和數(shù)據(jù)同步過程中沖突解決的復(fù)雜度而被廣泛使用。相比于關(guān)系型數(shù)據(jù)庫(kù),更容易做到跨設(shè)備跨版本兼容。
關(guān)系型數(shù)據(jù)庫(kù)(RelationalStore):一種關(guān)系型數(shù)據(jù)庫(kù),以行和列的形式存儲(chǔ)數(shù)據(jù),廣泛用于應(yīng)用中的關(guān)系型數(shù)據(jù)的處理,包括一系列的增、刪、改、查等接口,開發(fā)者也可以運(yùn)行自己定義的SQL語句來滿足復(fù)雜業(yè)務(wù)場(chǎng)景的需要。
通過用戶首選項(xiàng)實(shí)現(xiàn)數(shù)據(jù)持久化
場(chǎng)景介紹
用戶首選項(xiàng)為應(yīng)用提供Key-Value鍵值型的數(shù)據(jù)處理能力,支持應(yīng)用持久化輕量級(jí)數(shù)據(jù),并對(duì)其修改和查詢。當(dāng)用戶希望有一個(gè)全局唯一存儲(chǔ)的地方,可以采用用戶首選項(xiàng)來進(jìn)行存儲(chǔ)。Preferences會(huì)將該數(shù)據(jù)緩存在內(nèi)存中,當(dāng)用戶讀取的時(shí)候,能夠快速?gòu)膬?nèi)存中獲取數(shù)據(jù),當(dāng)需要持久化時(shí)可以使用flush接口將內(nèi)存中的數(shù)據(jù)寫入持久化文件中。Preferences會(huì)隨著存放的數(shù)據(jù)量越多而導(dǎo)致應(yīng)用占用的內(nèi)存越大,因此,Preferences不適合存放過多的數(shù)據(jù),適用的場(chǎng)景一般為應(yīng)用保存用戶的個(gè)性化設(shè)置(字體大小,是否開啟夜間模式)等。
運(yùn)作機(jī)制
如圖所示,用戶程序通過ArkTS接口調(diào)用用戶首選項(xiàng)讀寫對(duì)應(yīng)的數(shù)據(jù)文件。開發(fā)者可以將用戶首選項(xiàng)持久化文件的內(nèi)容加載到Preferences實(shí)例,每個(gè)文件唯一對(duì)應(yīng)到一個(gè)Preferences實(shí)例,系統(tǒng)會(huì)通過靜態(tài)容器將該實(shí)例存儲(chǔ)在內(nèi)存中,直到主動(dòng)從內(nèi)存中移除該實(shí)例或者刪除該文件。
應(yīng)用首選項(xiàng)的持久化文件保存在應(yīng)用沙箱內(nèi)部,可以通過context獲取其路徑。
圖1 用戶首選項(xiàng)運(yùn)作機(jī)制

約束限制
Key鍵為string類型,要求非空且長(zhǎng)度不超過80個(gè)字節(jié)。
如果Value值為string類型,請(qǐng)使用UTF-8編碼格式,可以為空,不為空時(shí)長(zhǎng)度不超過8192個(gè)字節(jié)。
內(nèi)存會(huì)隨著存儲(chǔ)數(shù)據(jù)量的增大而增大,所以存儲(chǔ)的數(shù)據(jù)量應(yīng)該是輕量級(jí)的,建議存儲(chǔ)的數(shù)據(jù)不超過一萬條,否則會(huì)在內(nèi)存方面產(chǎn)生較大的開銷。
接口說明
以下是用戶首選項(xiàng)持久化功能的相關(guān)接口,更多接口及使用方式請(qǐng)見用戶首選項(xiàng)。
| 接口名稱 | 描述 |
|---|---|
| getPreferencesSync(context: Context, options: Options): Preferences | 獲取Preferences實(shí)例。該接口存在異步接口。 |
| putSync(key: string, value: ValueType): void | 將數(shù)據(jù)寫入Preferences實(shí)例,可通過flush將Preferences實(shí)例持久化。該接口存在異步接口。 |
| hasSync(key: string): void | 檢查Preferences實(shí)例是否包含名為給定Key的存儲(chǔ)鍵值對(duì)。給定的Key值不能為空。該接口存在異步接口。 |
| getSync(key: string, defValue: ValueType): void | 獲取鍵對(duì)應(yīng)的值,如果值為null或者非默認(rèn)值類型,返回默認(rèn)數(shù)據(jù)defValue。該接口存在異步接口。 |
| deleteSync(key: string): void | 從Preferences實(shí)例中刪除名為給定Key的存儲(chǔ)鍵值對(duì)。該接口存在異步接口。 |
| flush(callback: AsyncCallback<void>): void | 將當(dāng)前Preferences實(shí)例的數(shù)據(jù)異步存儲(chǔ)到用戶首選項(xiàng)持久化文件中。 |
| on(type: 'change', callback: Callback<string>): void | 訂閱數(shù)據(jù)變更,訂閱的數(shù)據(jù)發(fā)生變更后,在執(zhí)行flush方法后,觸發(fā)callback回調(diào)。 |
| off(type: 'change', callback?: Callback<string>): void | 取消訂閱數(shù)據(jù)變更。 |
| deletePreferences(context: Context, options: Options, callback: AsyncCallback<void>): void | 從內(nèi)存中移除指定的Preferences實(shí)例。若Preferences實(shí)例有對(duì)應(yīng)的持久化文件,則同時(shí)刪除其持久化文件。 |
開發(fā)步驟
-
導(dǎo)入
@ohos.data.preferences模塊。import dataPreferences from '@ohos.data.preferences'; -
獲取Preferences實(shí)例。
Stage模型示例:
import UIAbility from '@ohos.app.ability.UIAbility';
import { BusinessError } from '@ohos.base';
import window from '@ohos.window';
let preferences: dataPreferences.Preferences | null = null;
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
let options: dataPreferences.Options = { name: 'myStore' };
preferences = dataPreferences.getPreferencesSync(this.context, options);
}
}
FA模型示例:
// 獲取context
import featureAbility from '@ohos.ability.featureAbility';
import { BusinessError } from '@ohos.base';
let context = featureAbility.getContext();
let options: dataPreferences.Options = { name: 'myStore' };
let preferences: dataPreferences.Preferences = dataPreferences.getPreferencesSync(context, options);
-
寫入數(shù)據(jù)。
使用putSync()方法保存數(shù)據(jù)到緩存的Preferences實(shí)例中。在寫入數(shù)據(jù)后,如有需要,可使用flush()方法將Preferences實(shí)例的數(shù)據(jù)存儲(chǔ)到持久化文件。
說明:
當(dāng)對(duì)應(yīng)的鍵已經(jīng)存在時(shí),putSync()方法會(huì)修改其值??梢允褂胔asSync()方法檢查是否存在對(duì)應(yīng)鍵值對(duì)。
示例代碼如下所示:
import util from '@ohos.util'; if (preferences.hasSync('startup')) { console.info("The key 'startup' is contained."); } else { console.info("The key 'startup' does not contain."); // 此處以此鍵值對(duì)不存在時(shí)寫入數(shù)據(jù)為例 preferences.putSync('startup', 'auto'); // 當(dāng)字符串有特殊字符時(shí),需要將字符串轉(zhuǎn)為Uint8Array類型再存儲(chǔ) let uInt8Array = new util.TextEncoder().encodeInto("~!@#¥%……&*()——+?"); preferences.putSync('uInt8', uInt8Array); } -
讀取數(shù)據(jù)。
使用getSync()方法獲取數(shù)據(jù),即指定鍵對(duì)應(yīng)的值。如果值為null或者非默認(rèn)值類型,則返回默認(rèn)數(shù)據(jù)。
示例代碼如下所示:
import util from '@ohos.util'; let val = preferences.getSync('startup', 'default'); console.info("The 'startup' value is " + val); // 當(dāng)獲取的值為帶有特殊字符的字符串時(shí),需要將獲取到的Uint8Array轉(zhuǎn)換為字符串 let uInt8Array : dataPreferences.ValueType = preferences.getSync('uInt8', new Uint8Array(0)); let textDecoder = util.TextDecoder.create('utf-8'); val = textDecoder.decodeWithStream(uInt8Array as Uint8Array); console.info("The 'uInt8' value is " + val); -
刪除數(shù)據(jù)。
使用deleteSync()方法刪除指定鍵值對(duì),示例代碼如下所示:
preferences.deleteSync('startup');
-
數(shù)據(jù)持久化。
應(yīng)用存入數(shù)據(jù)到Preferences實(shí)例后,可以使用flush()方法實(shí)現(xiàn)數(shù)據(jù)持久化。示例代碼如下所示:
preferences.flush((err: BusinessError) => { if (err) { console.error(`Failed to flush. Code:${err.code}, message:${err.message}`); return; } console.info('Succeeded in flushing.'); }) -
訂閱數(shù)據(jù)變更。
應(yīng)用訂閱數(shù)據(jù)變更需要指定observer作為回調(diào)方法。訂閱的Key值發(fā)生變更后,當(dāng)執(zhí)行flush()方法時(shí),observer被觸發(fā)回調(diào)。示例代碼如下所示:
let observer = (key: string) => { console.info('The key' + key + 'changed.'); } preferences.on('change', observer); // 數(shù)據(jù)產(chǎn)生變更,由'auto'變?yōu)?manual' preferences.put('startup', 'manual', (err: BusinessError) => { if (err) { console.error(`Failed to put the value of 'startup'. Code:${err.code},message:${err.message}`); return; } console.info("Succeeded in putting the value of 'startup'."); if (preferences !== null) { preferences.flush((err: BusinessError) => { if (err) { console.error(`Failed to flush. Code:${err.code}, message:${err.message}`); return; } console.info('Succeeded in flushing.'); }) } }) -
刪除指定文件。
使用deletePreferences()方法從內(nèi)存中移除指定文件對(duì)應(yīng)的Preferences實(shí)例,包括內(nèi)存中的數(shù)據(jù)。若該P(yáng)reference存在對(duì)應(yīng)的持久化文件,則同時(shí)刪除該持久化文件,包括指定文件及其備份文件、損壞文件。
說明:
調(diào)用該接口后,應(yīng)用不允許再使用該P(yáng)references實(shí)例進(jìn)行數(shù)據(jù)操作,否則會(huì)出現(xiàn)數(shù)據(jù)一致性問題。
成功刪除后,數(shù)據(jù)及文件將不可恢復(fù)。
示例代碼如下所示:
let options: dataPreferences.Options = { name: 'myStore' };
dataPreferences.deletePreferences(this.context, options, (err: BusinessError) => {
if (err) {
console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);
return;
}
console.info('Succeeded in deleting preferences.');
})
寫在最后
- 如果你覺得這篇內(nèi)容對(duì)你還蠻有幫助,我想邀請(qǐng)你幫我三個(gè)小忙:
- 點(diǎn)贊,轉(zhuǎn)發(fā),有你們的 『點(diǎn)贊和評(píng)論』,才是我創(chuàng)造的動(dòng)力。
- 關(guān)注小編,同時(shí)可以期待后續(xù)文章ing??,不定期分享原創(chuàng)知識(shí)。
- 想要獲取更多完整鴻蒙最新學(xué)習(xí)知識(shí)點(diǎn),請(qǐng)移步前往小編:
https://gitee.com/MNxiaona/733GH/blob/master/jianshu
