本文字数:约3200字 | 预计阅读时间:13分钟
前置知识:建议先学习本系列前五篇,特别是网络请求与数据处理
实战价值:掌握本地存储,让应用具备离线能力,提升用户体验
系列导航:本文是《鸿蒙开发系列》第6篇,下篇将讲解服务卡片开发实战
一、本地存储概述 在移动应用开发中,本地数据存储是必不可少的功能。它可以让应用:
实现离线使用:在没有网络的情况下正常使用
提升性能:减少网络请求,快速加载数据
保存用户偏好:记住用户的设置和偏好
缓存数据:临时存储网络数据,减少流量消耗
鸿蒙提供了多种本地存储方案,每种方案都有其适用的场景。
二、Preferences:轻量级键值存储 Preferences是鸿蒙提供的轻量级存储方案,适合存储简单的键值对数据,如用户设置、登录状态等。
2.1 基本使用 typescript
import dataPreferences from '@ohos.data.preferences';
class PreferencesManager { private preferences: dataPreferences.Preferences | null = null;
// 初始化Preferences async init(context: any, name: string = 'myPreferences') { try { this.preferences = await dataPreferences.getPreferences(context, name); console.log('Preferences初始化成功'); } catch (error) { console.error('Preferences初始化失败:', error); } }
// 保存数据 async set(key: string, value: dataPreferences.ValueType) { if (!this.preferences) { throw new Error('Preferences未初始化'); }
try {
await this.preferences.put(key, value);
await this.preferences.flush(); // 持久化到磁盘
return true;
} catch (error) {
console.error('保存数据失败:', error);
return false;
}
}
// 获取数据 async get(key: string, defaultValue: dataPreferences.ValueType = '') { if (!this.preferences) { throw new Error('Preferences未初始化'); }
try {
const value = await this.preferences.get(key, defaultValue);
return value;
} catch (error) {
console.error('获取数据失败:', error);
return defaultValue;
}
}
// 删除数据 async delete(key: string) { if (!this.preferences) { throw new Error('Preferences未初始化'); }
try {
await this.preferences.delete(key);
await this.preferences.flush();
return true;
} catch (error) {
console.error('删除数据失败:', error);
return false;
}
}
// 清空所有数据 async clear() { if (!this.preferences) { throw new Error('Preferences未初始化'); }
try {
await this.preferences.clear();
await this.preferences.flush();
return true;
} catch (error) {
console.error('清空数据失败:', error);
return false;
}
} }
// 全局实例 export const preferencesManager = new PreferencesManager(); 2.2 在应用中使用 typescript
@Entry @Component struct SettingsPage { @State username: string = ''; @State rememberMe: boolean = false; @State fontSize: number = 16;
async aboutToAppear() { // 初始化Preferences await preferencesManager.init(getContext(this));
// 加载保存的设置
this.username = (await preferencesManager.get('username', '')) as string;
this.rememberMe = (await preferencesManager.get('rememberMe', false)) as boolean;
this.fontSize = (await preferencesManager.get('fontSize', 16)) as number;
}
async saveSettings() { await preferencesManager.set('username', this.username); await preferencesManager.set('rememberMe', this.rememberMe); await preferencesManager.set('fontSize', this.fontSize);
// 显示保存成功提示
prompt.showToast({ message: '设置已保存' });
}
build() { Column({ space: 20 }) { Text('应用设置') .fontSize(24) .fontWeight(FontWeight.Bold)
// 用户名设置
Column({ space: 8 }) {
Text('用户名')
.fontSize(16)
.fontColor('#333333')
TextInput({ placeholder: '请输入用户名' })
.width('100%')
.height(48)
.fontSize(this.fontSize)
.value(this.username)
.onChange((value: string) => {
this.username = value;
})
}
// 记住我选项
Row({ space: 10 }) {
Checkbox()
.select(this.rememberMe)
.onChange((checked: boolean) => {
this.rememberMe = checked;
})
Text('记住登录状态')
.fontSize(16)
}
// 字体大小设置
Column({ space: 8 }) {
Text(`字体大小:${this.fontSize}`)
.fontSize(16)
Slider({
value: this.fontSize,
min: 12,
max: 24,
step: 1,
style: SliderStyle.InSet
})
.width('100%')
.onChange((value: number) => {
this.fontSize = value;
})
}
// 保存按钮
Button('保存设置')
.width('100%')
.height(50)
.fontSize(18)
.onClick(() => {
this.saveSettings();
})
}
.width('100%')
.height('100%')
.padding(20)
} } 三、关系型数据库:SQLite 对于需要复杂查询和事务支持的数据存储,鸿蒙提供了关系型数据库(基于SQLite)的支持。
3.1 数据库管理类 typescript
import relationalStore from '@ohos.data.relationalStore';
// 定义用户表结构 const USER_TABLE = 'users'; const USER_SCHEMA = { tableName: USER_TABLE, columns: [ { fieldName: 'id', columnName: 'id', type: relationalStore.ValueType.INTEGER, isPrimaryKey: true }, { fieldName: 'name', columnName: 'name', type: relationalStore.ValueType.STRING }, { fieldName: 'email', columnName: 'email', type: relationalStore.ValueType.STRING }, { fieldName: 'age', columnName: 'age', type: relationalStore.ValueType.INTEGER }, { fieldName: 'createdAt', columnName: 'created_at', type: relationalStore.ValueType.INTEGER }, { fieldName: 'updatedAt', columnName: 'updated_at', type: relationalStore.ValueType.INTEGER } ] };
class DatabaseManager { private rdbStore: relationalStore.RdbStore | null = null;
// 初始化数据库 async init(context: any) { const config: relationalStore.StoreConfig = { name: 'myApp.db', securityLevel: relationalStore.SecurityLevel.S1 };
try {
this.rdbStore = await relationalStore.getRdbStore(context, config);
// 创建用户表
await this.createTable(USER_SCHEMA);
console.log('数据库初始化成功');
} catch (error) {
console.error('数据库初始化失败:', error);
}
}
// 创建表 private async createTable(schema: any) { if (!this.rdbStore) return;
const sql = `
CREATE TABLE IF NOT EXISTS ${schema.tableName} (
${schema.columns.map((col: any) =>
`${col.columnName} ${this.getSqlType(col.type)} ${col.isPrimaryKey ? 'PRIMARY KEY' : ''}`
).join(', ')}
)
`;
await this.rdbStore.executeSql(sql);
}
// 类型映射 private getSqlType(type: relationalStore.ValueType): string { switch (type) { case relationalStore.ValueType.INTEGER: return 'INTEGER'; case relationalStore.ValueType.STRING: return 'TEXT'; case relationalStore.ValueType.FLOAT: return 'REAL'; case relationalStore.ValueType.BLOB: return 'BLOB'; default: return 'TEXT'; } }
// 插入用户 async insertUser(user: { name: string, email: string, age: number }) { if (!this.rdbStore) return false;
const valueBucket: relationalStore.ValuesBucket = {
'name': user.name,
'email': user.email,
'age': user.age,
'created_at': Date.now(),
'updated_at': Date.now()
};
try {
const rowId = await this.rdbStore.insert(USER_TABLE, valueBucket);
return rowId > 0;
} catch (error) {
console.error('插入用户失败:', error);
return false;
}
}
// 查询所有用户 async getAllUsers(): Promise<any[]> { if (!this.rdbStore) return [];
const predicates = new relationalStore.RdbPredicates(USER_TABLE);
predicates.orderByAsc('created_at');
try {
const resultSet = await this.rdbStore.query(predicates, [
'id', 'name', 'email', 'age', 'created_at', 'updated_at'
]);
const users: any[] = [];
while (resultSet.goToNextRow()) {
users.push({
id: resultSet.getDouble(resultSet.getColumnIndex('id')),
name: resultSet.getString(resultSet.getColumnIndex('name')),
email: resultSet.getString(resultSet.getColumnIndex('email')),
age: resultSet.getDouble(resultSet.getColumnIndex('age')),
createdAt: resultSet.getDouble(resultSet.getColumnIndex('created_at')),
updatedAt: resultSet.getDouble(resultSet.getColumnIndex('updated_at'))
});
}
resultSet.close();
return users;
} catch (error) {
console.error('查询用户失败:', error);
return [];
}
}
// 更新用户 async updateUser(id: number, updates: Partial<{ name: string, email: string, age: number }>) { if (!this.rdbStore) return false;
const predicates = new relationalStore.RdbPredicates(USER_TABLE);
predicates.equalTo('id', id);
const valueBucket: relationalStore.ValuesBucket = {
'updated_at': Date.now()
};
if (updates.name) valueBucket['name'] = updates.name;
if (updates.email) valueBucket['email'] = updates.email;
if (updates.age) valueBucket['age'] = updates.age;
try {
const rowsUpdated = await this.rdbStore.update(valueBucket, predicates);
return rowsUpdated > 0;
} catch (error) {
console.error('更新用户失败:', error);
return false;
}
}
// 删除用户 async deleteUser(id: number) { if (!this.rdbStore) return false;
const predicates = new relationalStore.RdbPredicates(USER_TABLE);
predicates.equalTo('id', id);
try {
const rowsDeleted = await this.rdbStore.delete(predicates);
return rowsDeleted > 0;
} catch (error) {
console.error('删除用户失败:', error);
return false;
}
}
// 事务操作 async batchInsertUsers(users: Array<{ name: string, email: string, age: number }>) { if (!this.rdbStore) return false;
try {
await this.rdbStore.beginTransaction();
for (const user of users) {
await this.insertUser(user);
}
await this.rdbStore.commit();
return true;
} catch (error) {
await this.rdbStore.rollback();
console.error('批量插入失败:', error);
return false;
}
} }
export const databaseManager = new DatabaseManager(); 3.2 用户管理界面 typescript
@Entry @Component struct UserManagerPage { @State users: any[] = []; @State loading: boolean = false; @State newUserName: string = ''; @State newUserEmail: string = ''; @State newUserAge: string = '';
async aboutToAppear() { await databaseManager.init(getContext(this)); this.loadUsers(); }
async loadUsers() { this.loading = true; this.users = await databaseManager.getAllUsers(); this.loading = false; }
async addUser() { if (!this.newUserName.trim() || !this.newUserEmail.trim()) { prompt.showToast({ message: '请填写完整信息' }); return; }
const age = parseInt(this.newUserAge) || 0;
const success = await databaseManager.insertUser({
name: this.newUserName,
email: this.newUserEmail,
age: age
});
if (success) {
prompt.showToast({ message: '用户添加成功' });
this.newUserName = '';
this.newUserEmail = '';
this.newUserAge = '';
this.loadUsers();
}
}
async deleteUser(id: number) { const success = await databaseManager.deleteUser(id); if (success) { prompt.showToast({ message: '用户删除成功' }); this.loadUsers(); } }
build() { Column({ space: 20 }) { Text('用户管理') .fontSize(24) .fontWeight(FontWeight.Bold)
// 添加用户表单
Column({ space: 12 }) {
TextInput({ placeholder: '姓名' })
.width('100%')
.height(48)
.value(this.newUserName)
.onChange((value: string) => {
this.newUserName = value;
})
TextInput({ placeholder: '邮箱' })
.width('100%')
.height(48)
.value(this.newUserEmail)
.onChange((value: string) => {
this.newUserEmail = value;
})
TextInput({ placeholder: '年龄' })
.width('100%')
.height(48)
.value(this.newUserAge)
.onChange((value: string) => {
this.newUserAge = value;
})
Button('添加用户')
.width('100%')
.height(50)
.onClick(() => {
this.addUser();
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 用户列表
if (this.loading) {
LoadingProgress()
.width(50)
.height(50)
} else {
List({ space: 12 }) {
ForEach(this.users, (user: any) => {
ListItem() {
UserItem({
user: user,
onDelete: () => {
this.deleteUser(user.id);
}
})
}
})
}
.layoutWeight(1)
}
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
} }
@Component struct UserItem { @Prop user: any; @Prop onDelete: () => void;
build() { Row({ space: 15 }) { Column({ space: 5 }) { Text(this.user.name) .fontSize(16) .fontWeight(FontWeight.Bold)
Text(this.user.email)
.fontSize(14)
.fontColor('#666666')
Text(`年龄:${this.user.age}`)
.fontSize(12)
.fontColor('#999999')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Button('删除')
.width(80)
.height(36)
.fontSize(14)
.backgroundColor('#FF3B30')
.onClick(() => {
this.onDelete();
})
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
} } 四、文件存储 对于需要存储大型文件或自定义格式的数据,可以使用文件系统API。
4.1 文件管理类 typescript
import fs from '@ohos.file.fs'; import fileIo from '@ohos.fileio';
class FileManager { // 获取应用文件目录 private getFilesDir(context: any): string { return context.filesDir; }
// 获取缓存目录 private getCacheDir(context: any): string { return context.cacheDir; }
// 检查文件是否存在 async fileExists(context: any, filePath: string): Promise { try { await fileIo.access(filePath); return true; } catch { return false; } }
// 写入文本文件
async writeTextFile(context: any, fileName: string, content: string): Promise {
const filePath = ${this.getFilesDir(context)}/${fileName};
try {
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
await fileIo.write(file.fd, content);
await fileIo.close(file.fd);
return true;
} catch (error) {
console.error('写入文件失败:', error);
return false;
}
}
// 读取文本文件
async readTextFile(context: any, fileName: string): Promise {
const filePath = ${this.getFilesDir(context)}/${fileName};
try {
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_ONLY);
const stat = await fileIo.stat(filePath);
const buffer = new ArrayBuffer(stat.size);
await fileIo.read(file.fd, buffer);
await fileIo.close(file.fd);
const textDecoder = new util.TextDecoder('utf-8');
return textDecoder.decode(buffer);
} catch (error) {
console.error('读取文件失败:', error);
return '';
}
}
// 保存JSON数据 async saveJson(context: any, fileName: string, data: any): Promise { const jsonString = JSON.stringify(data, null, 2); return this.writeTextFile(context, fileName, jsonString); }
// 读取JSON数据 async loadJson<T = any>(context: any, fileName: string): Promise<T | null> { const content = await this.readTextFile(context, fileName); if (!content) return null;
try {
return JSON.parse(content) as T;
} catch (error) {
console.error('解析JSON失败:', error);
return null;
}
}
// 保存图片到缓存
async saveImageToCache(context: any, imageUrl: string, imageData: ArrayBuffer): Promise {
const cacheDir = this.getCacheDir(context);
const fileName = ${Date.now()}_${imageUrl.split('/').pop()};
const filePath = ${cacheDir}/${fileName};
try {
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
await fileIo.write(file.fd, imageData);
await fileIo.close(file.fd);
return filePath;
} catch (error) {
console.error('保存图片失败:', error);
return '';
}
}
// 获取缓存大小 async getCacheSize(context: any): Promise { const cacheDir = this.getCacheDir(context);
try {
const dir = await fileIo.opendir(cacheDir);
let totalSize = 0;
let dirent = await dir.read();
while (dirent) {
const filePath = `${cacheDir}/${dirent.name}`;
const stat = await fileIo.stat(filePath);
totalSize += stat.size;
dirent = await dir.read();
}
await dir.close();
return totalSize;
} catch (error) {
console.error('获取缓存大小失败:', error);
return 0;
}
}
// 清空缓存 async clearCache(context: any): Promise { const cacheDir = this.getCacheDir(context);
try {
const dir = await fileIo.opendir(cacheDir);
let dirent = await dir.read();
while (dirent) {
const filePath = `${cacheDir}/${dirent.name}`;
await fileIo.unlink(filePath);
dirent = await dir.read();
}
await dir.close();
return true;
} catch (error) {
console.error('清空缓存失败:', error);
return false;
}
} }
export const fileManager = new FileManager(); 4.2 文件操作界面 typescript
@Entry @Component struct FileManagerPage { @State notes: string = ''; @State cacheSize: string = '0 KB'; @State loading: boolean = false;
private context = getContext(this);
async aboutToAppear() { this.loadNotes(); this.loadCacheSize(); }
async loadNotes() { const savedNotes = await fileManager.readTextFile(this.context, 'notes.txt'); this.notes = savedNotes || ''; }
async saveNotes() { const success = await fileManager.writeTextFile(this.context, 'notes.txt', this.notes); if (success) { prompt.showToast({ message: '保存成功' }); } }
async loadCacheSize() { this.loading = true; const sizeInBytes = await fileManager.getCacheSize(this.context); this.cacheSize = this.formatFileSize(sizeInBytes); this.loading = false; }
async clearAllCache() { const success = await fileManager.clearCache(this.context); if (success) { prompt.showToast({ message: '缓存已清除' }); this.loadCacheSize(); } }
private formatFileSize(bytes: number): string { if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
build() { Column({ space: 20 }) { Text('文件管理') .fontSize(24) .fontWeight(FontWeight.Bold)
// 笔记编辑器
Column({ space: 12 }) {
Text('个人笔记')
.fontSize(18)
.fontWeight(FontWeight.Medium)
TextArea({ placeholder: '请输入笔记内容...' })
.width('100%')
.height(200)
.value(this.notes)
.onChange((value: string) => {
this.notes = value;
})
Button('保存笔记')
.width('100%')
.height(50)
.onClick(() => {
this.saveNotes();
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 缓存管理
Column({ space: 12 }) {
Text('缓存管理')
.fontSize(18)
.fontWeight(FontWeight.Medium)
Row() {
Text('缓存大小:')
.fontSize(16)
if (this.loading) {
LoadingProgress()
.width(20)
.height(20)
} else {
Text(this.cacheSize)
.fontSize(16)
.fontColor('#007DFF')
}
}
Button('清除缓存')
.width('100%')
.height(50)
.backgroundColor('#FF9500')
.onClick(() => {
this.clearAllCache();
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
} } 五、数据加密与安全 对于敏感数据,需要进行加密存储。
5.1 数据加密工具 typescript
import cryptoFramework from '@ohos.security.cryptoFramework';
class CryptoManager { // 生成密钥 async generateKey(): Promise { try { const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256'); const symKey = await symKeyGenerator.generateSymKey(); const keyData = await symKey.getEncoded();
// 转换为base64字符串
const base64Key = this.arrayBufferToBase64(keyData.data);
return base64Key;
} catch (error) {
console.error('生成密钥失败:', error);
throw error;
}
}
// 加密数据 async encrypt(text: string, keyBase64: string): Promise { try { const keyData = this.base64ToArrayBuffer(keyBase64);
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
const symKey = await symKeyGenerator.convertKey({ data: keyData });
const cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7');
await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, null);
const input = { data: this.stringToArrayBuffer(text) };
const encrypted = await cipher.doFinal(input);
return this.arrayBufferToBase64(encrypted.data);
} catch (error) {
console.error('加密失败:', error);
throw error;
}
}
// 解密数据 async decrypt(encryptedBase64: string, keyBase64: string): Promise { try { const keyData = this.base64ToArrayBuffer(keyBase64); const encryptedData = this.base64ToArrayBuffer(encryptedBase64);
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
const symKey = await symKeyGenerator.convertKey({ data: keyData });
const cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7');
await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, null);
const input = { data: encryptedData };
const decrypted = await cipher.doFinal(input);
return this.arrayBufferToString(decrypted.data);
} catch (error) {
console.error('解密失败:', error);
throw error;
}
}
// 工具方法 private arrayBufferToBase64(buffer: ArrayBuffer): string { let binary = ''; const bytes = new Uint8Array(buffer); for (let i = 0; i < bytes.byteLength; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary); }
private base64ToArrayBuffer(base64: string): ArrayBuffer { const binary = atob(base64); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes.buffer; }
private stringToArrayBuffer(str: string): ArrayBuffer { const encoder = new TextEncoder(); return encoder.encode(str).buffer; }
private arrayBufferToString(buffer: ArrayBuffer): string { const decoder = new TextDecoder('utf-8'); return decoder.decode(buffer); } }
export const cryptoManager = new CryptoManager(); 5.2 安全存储示例 typescript
@Entry @Component struct SecureStoragePage { @State secretKey: string = ''; @State plainText: string = ''; @State encryptedText: string = ''; @State decryptedText: string = ''; @State loading: boolean = false;
async generateKey() { this.loading = true; try { this.secretKey = await cryptoManager.generateKey(); await preferencesManager.set('secret_key', this.secretKey); prompt.showToast({ message: '密钥已生成并保存' }); } catch (error) { console.error('生成密钥失败:', error); } this.loading = false; }
async loadKey() { this.secretKey = (await preferencesManager.get('secret_key', '')) as string; }
async encryptData() { if (!this.secretKey) { prompt.showToast({ message: '请先生成或加载密钥' }); return; }
if (!this.plainText) {
prompt.showToast({ message: '请输入要加密的文本' });
return;
}
this.loading = true;
try {
this.encryptedText = await cryptoManager.encrypt(this.plainText, this.secretKey);
prompt.showToast({ message: '加密成功' });
} catch (error) {
console.error('加密失败:', error);
prompt.showToast({ message: '加密失败' });
}
this.loading = false;
}
async decryptData() { if (!this.secretKey) { prompt.showToast({ message: '请先加载密钥' }); return; }
if (!this.encryptedText) {
prompt.showToast({ message: '请输入要解密的文本' });
return;
}
this.loading = true;
try {
this.decryptedText = await cryptoManager.decrypt(this.encryptedText, this.secretKey);
prompt.showToast({ message: '解密成功' });
} catch (error) {
console.error('解密失败:', error);
prompt.showToast({ message: '解密失败' });
}
this.loading = false;
}
aboutToAppear() { preferencesManager.init(getContext(this)); this.loadKey(); }
build() { Column({ space: 20 }) { Text('安全存储') .fontSize(24) .fontWeight(FontWeight.Bold)
// 密钥管理
Column({ space: 12 }) {
Text('密钥管理')
.fontSize(18)
.fontWeight(FontWeight.Medium)
Row({ space: 10 }) {
Button('生成密钥')
.width(120)
.height(40)
.onClick(() => {
this.generateKey();
})
Button('加载密钥')
.width(120)
.height(40)
.onClick(() => {
this.loadKey();
})
}
if (this.secretKey) {
Text('密钥已加载')
.fontSize(14)
.fontColor('#34C759')
}
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 加密区域
Column({ space: 12 }) {
Text('加密')
.fontSize(18)
.fontWeight(FontWeight.Medium)
TextInput({ placeholder: '请输入要加密的文本' })
.width('100%')
.height(80)
.value(this.plainText)
.onChange((value: string) => {
this.plainText = value;
})
Button('加密')
.width('100%')
.height(50)
.onClick(() => {
this.encryptData();
})
if (this.encryptedText) {
Text('加密结果:')
.fontSize(14)
Text(this.encryptedText)
.fontSize(12)
.fontColor('#666666')
.maxLines(3)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 解密区域
Column({ space: 12 }) {
Text('解密')
.fontSize(18)
.fontWeight(FontWeight.Medium)
TextInput({ placeholder: '请输入要解密的文本' })
.width('100%')
.height(80)
.value(this.encryptedText)
.onChange((value: string) => {
this.encryptedText = value;
})
Button('解密')
.width('100%')
.height(50)
.onClick(() => {
this.decryptData();
})
if (this.decryptedText) {
Text('解密结果:')
.fontSize(14)
Text(this.decryptedText)
.fontSize(14)
.fontColor('#333333')
}
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
if (this.loading) {
LoadingProgress()
.width(50)
.height(50)
}
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
} } 六、存储方案选择指南 存储方案 适用场景 优点 缺点 Preferences 用户设置、登录状态、简单配置 使用简单、性能好 不适合大量数据、复杂查询 关系型数据库 用户数据、消息记录、复杂数据结构 支持复杂查询、事务 使用相对复杂、需要SQL知识 文件存储 大文件、图片、文档、自定义格式数据 灵活、适合大量数据 需要手动管理文件、无内置查询功能 加密存储 敏感数据(密码、支付信息) 安全性高 性能开销大、需要密钥管理 七、最佳实践 7.1 分层存储策略 typescript
class StorageStrategy { // 内存缓存(最快) private memoryCache = new Map<string, any>();
// Preferences(中等速度) private preferences: PreferencesManager;
// 数据库/文件(最慢,但持久化) private database: DatabaseManager; private fileManager: FileManager;
constructor() { this.preferences = new PreferencesManager(); this.database = new DatabaseManager(); this.fileManager = new FileManager(); }
// 获取数据(多层缓存) async getData(key: string): Promise<T | null> { // 1. 检查内存缓存 if (this.memoryCache.has(key)) { return this.memoryCache.get(key); }
// 2. 检查Preferences
const prefData = await this.preferences.get(key);
if (prefData) {
this.memoryCache.set(key, prefData);
return prefData as T;
}
// 3. 检查数据库/文件
// ... 根据key的类型选择不同的存储方式
return null;
} } 7.2 数据同步策略 typescript
class DataSyncManager { // 同步本地和远程数据 async syncData( localKey: string, remoteFetch: () => Promise, shouldUpdate: (local: T, remote: T) => boolean ): Promise { // 1. 从本地获取数据 const localData = await this.getLocalData(localKey);
// 2. 从远程获取数据
let remoteData: T;
try {
remoteData = await remoteFetch();
} catch (error) {
// 网络失败,返回本地数据
console.warn('网络请求失败,使用本地数据');
return localData;
}
// 3. 比较数据,决定是否更新
if (!localData || shouldUpdate(localData, remoteData)) {
await this.saveLocalData(localKey, remoteData);
return remoteData;
}
return localData;
} } 八、总结与下期预告 8.1 本文要点回顾 Preferences:轻量级键值存储,适合简单配置
关系型数据库:复杂数据存储,支持SQL查询
文件存储:大文件和自定义格式数据存储
数据加密:敏感数据的安全存储
存储策略:如何根据场景选择合适的存储方案
8.2 下期预告:《鸿蒙开发之:服务卡片开发实战》 下篇文章将深入讲解:
服务卡片的基本概念和使用场景
卡片布局和样式设计
卡片数据更新和交互
卡片配置和部署
实战:创建各种类型的服务卡片
动手挑战 任务1:实现备忘录应用 要求:
使用数据库存储备忘录数据
支持备忘录的增删改查
支持备忘录分类和标签
实现数据备份和恢复功能
任务2:实现图片收藏应用 要求:
使用文件系统保存图片
使用数据库保存图片元数据
支持图片的分类和搜索
实现图片加密存储
任务3:实现数据同步框架 要求:
支持本地和远程数据同步
实现冲突解决策略
支持离线编辑和自动同步
实现数据版本控制
将你的代码分享到评论区,我会挑选优秀实现进行详细点评!
常见问题解答 Q:Preferences和数据库有什么区别? A:Preferences适合存储简单的键值对,如用户设置;数据库适合存储结构化数据,支持复杂查询。
Q:如何选择文件存储还是数据库存储? A:如果是结构化数据且需要查询,用数据库;如果是文件、图片或自定义格式,用文件存储。
Q:加密存储会影响性能吗? A:会有一定性能影响,但对于敏感数据,安全比性能更重要。可以对关键数据进行加密,非敏感数据明文存储。
Q:如何备份用户数据? A:可以将数据库或重要文件打包,保存到云端或设备外部存储。
PS:现在HarmonyOS应用开发者认证正在做活动,初级和高级都可以免费学习及考试,赶快加入班级学习啦:【注意,考试只能从此唯一链接进入】 developer.huawei.com/consumer/cn…