鸿蒙开发总结(二):数据存储与线程通讯

136 阅读6分钟

在鸿蒙应用开发中,数据存储和线程通讯是两个关键的技术点。

数据存储

鸿蒙提供了多种数据存储解决方案,以满足不同场景的需求。

LocalStorage

轻量级数据存储,适用于临时保存简单数据,如用户偏好设置、临时状态等。以下是使用 LocalStorage 存储和读取简单数据的示例代码:

// 存储数据
import storage from '@ohos.data.storage';
let localStorage = storage.getLocalStorageSync();
localStorage.setItem('userTheme', 'dark');
// 读取数据
let theme = localStorage.getItem('userTheme');
console.log('用户主题设置:', theme);

AppStorage

管理应用状态的存储机制,用于不同组件间共享数据,实现数据的响应式更新。假设在一个包含多个页面的鸿蒙应用中,有一个全局的用户登录状态需要在不同页面间共享,可利用 AppStorage 实现:

import { AppStorage } from '@ohos.appstorage';
// 创建AppStorage实例
const appStorage = new AppStorage();
// 存储用户登录状态
appStorage.set('isLoggedIn', true);
// 在其他组件中获取该状态
let isLoggedIn = appStorage.get('isLoggedIn');
console.log('当前用户登录状态:', isLoggedIn);

PersistentStorage

实现数据的持久化存储,适用于需要长期保存的数据,如用户的历史记录、配置信息等。持久化存储方式的选择对于应用的性能和用户体验有着直接的影响。面试中可能会讨论不同存储方式的特点和适用场景。

持久化存储方式

鸿蒙中的持久化存储方式包括 Preferences、PersistentStorage 和 SQL 数据库。

Preferences

轻量级的键值对存储,以 XML 文件形式存储数据。以下是使用 Preferences 进行数据存储和读取的代码:

import ohos.data.preferences.Preferences;
import ohos.data.preferences.PreferencesFactory;
import java.util.Map;
import java.util.Set;
// 获取Preferences实例
Preferences preferences = PreferencesFactory.getPreferences(getContext(), "my_preferences");
// 存储数据
preferences.putString("username", "JohnDoe");
preferences.putInt("userAge", 30);
preferences.flush();
// 读取数据
String username = preferences.getString("username", "");
int userAge = preferences.getInt("userAge", 0);
System.out.println("用户名: " + username + ", 年龄: " + userAge);

PersistentStorage

基于文件的持久化存储,支持异步操作。下面展示如何使用 PersistentStorage 异步保存和读取用户配置文件:

import storage from '@ohos.data.storage';
// 异步保存数据
async function saveUserData(userData) {
    let persistentStorage = await storage.getPersistentStorage('user_data.json');
    await persistentStorage.setItem('userConfig', JSON.stringify(userData));
}
// 异步读取数据
async function getUserData() {
    let persistentStorage = await storage.getPersistentStorage('user_data.json');
    let userConfig = await persistentStorage.getItem('userConfig');
    return JSON.parse(userConfig);
}

SQL 数据库

基于 SQLite 的关系型数据库存储方式,适合存储结构化数据。例如,在一个任务管理应用中,使用 SQL 数据库存储任务信息:

import ohos.data.rdb.*;
import ohos.data.rdb.RdbStore;
import java.util.ArrayList;
import java.util.List;
// 创建数据库帮助类
class TaskDBHelper extends RdbOpenHelper {
    public TaskDBHelper(Context context, String name, RdbStoreConfig config, int version) {
        super(context, name, config, version);
    }
    @Override
    public void onCreate(RdbStore rdbStore) {
        String createTableSql = "CREATE TABLE tasks (id INTEGER PRIMARY KEY AUTOINCREMENT, task_name TEXT, is_completed BOOLEAN)";
        rdbStore.executeSql(createTableSql);
    }
    @Override
    public void onUpgrade(RdbStore rdbStore, int oldVersion, int newVersion) {
        // 数据库升级逻辑
    }
}
// 插入任务数据
void insertTask(RdbStore rdbStore, String taskName, boolean isCompleted) {
    ValuesBucket valuesBucket = new ValuesBucket();
    valuesBucket.putString("task_name", taskName);
    valuesBucket.putBoolean("is_completed", isCompleted);
    rdbStore.insert("tasks", valuesBucket);
}
// 查询任务数据
List<String> queryTasks(RdbStore rdbStore) {
    List<String> tasks = new ArrayList<>();
    String[] columns = {"task_name"};
    RdbPredicates predicates = new RdbPredicates("tasks");
    ResultSet resultSet = rdbStore.query(predicates, columns);
    while (resultSet.next()) {
        String taskName = resultSet.getString(resultSet.getColumnIndexForName("task_name"));
        tasks.add(taskName);
    }
    resultSet.close();
    return tasks;
}

理解这些持久化存储方式的优缺点和使用场景对于开发者来说至关重要。面试时可能会探讨如何选择合适的存储方式以及如何在实际开发中实现数据的持久化。

生命周期理解

生命周期的理解对于鸿蒙开发至关重要,它涵盖了应用、页面和组件等多个层面。

应用生命周期

从应用启动到销毁的整个过程,包括应用的创建、初始化、前台运行、后台运行和销毁等阶段。以下是一个应用生命周期的示例代码:

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MainAbility extends Ability {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00200, "MainAbility");
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        HiLog.info(LABEL, "应用启动,执行初始化操作");
        // 应用启动时的初始化操作,如加载配置文件等
    }
    @Override
    public void onActive() {
        super.onActive();
        HiLog.info(LABEL, "应用进入前台");
        // 应用进入前台时的操作,如更新UI显示
    }
    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
        HiLog.info(LABEL, "应用从后台切换到前台");
        // 应用从后台切换到前台时的操作
    }
    @Override
    public void onBackground(Intent intent) {
        super.onBackground(intent);
        HiLog.info(LABEL, "应用进入后台");
        // 应用进入后台时的操作,如保存数据等
    }
    @Override
    public void onStop() {
        super.onStop();
        HiLog.info(LABEL, "应用停止,执行清理操作");
        // 应用停止时的清理操作,如释放资源等
    }
}

页面生命周期

针对 @Entry 修饰的组件,即页面,管理页面的显示和隐藏,处理页面间的跳转。下面是一个页面生命周期的示例:

import { AbilitySlice } from '@ohos.app.ability';
import { Intent } from '@ohos.app.ability';
import Log from '@ohos.hiviewdfx';
@Entry
export default class MainAbilitySlice extends AbilitySlice {
    private TAG = 'MainAbilitySlice';
    onStart(intent: Intent) {
        super.onStart(intent);
        Log.info(this.TAG, '页面启动');
        // 页面启动时的操作,如加载页面布局
    }
    onActive() {
        super.onActive();
        Log.info(this.TAG, '页面显示在前台');
        // 页面显示在前台时的操作,如更新页面数据
    }
    onForeground(intent: Intent) {
        super.onForeground(intent);
        Log.info(this.TAG, '页面从后台切换到前台');
        // 页面从后台切换到前台时的操作
    }
    onBackground(intent: Intent) {
        super.onBackground(intent);
        Log.info(this.TAG, '页面进入后台');
        // 页面进入后台时的操作,如暂停动画等
    }
    onStop() {
        super.onStop();
        Log.info(this.TAG, '页面停止');
        // 页面停止时的操作,如清理临时数据
    }
}

组件生命周期

自定义组件从创建到销毁或复用的过程。例如一个自定义按钮组件的生命周期示例:

import { Component } from '@ohos.components';
import Log from '@ohos.hiviewdfx';
@Component
struct CustomButton {
    private TAG = 'CustomButton';
    build() {
        Log.info(this.TAG, '组件创建');
        // 构建组件UI
    }
    onPageShow() {
        Log.info(this.TAG, '组件显示');
        // 组件显示时的操作,如初始化组件状态
    }
    onPageHide() {
        Log.info(this.TAG, '组件隐藏');
        // 组件隐藏时的操作,如保存组件数据
    }
    onDestroy() {
        Log.info(this.TAG, '组件销毁');
        // 组件销毁时的操作,如释放组件资源
    }
}

深入理解生命周期对于开发者来说至关重要,它影响着应用的性能和用户体验。面试中可能会考察对生命周期管理的理解以及如何在实际开发中应用这些概念。

线程通讯

在鸿蒙系统中,主线程通常用于处理 UI 相关的任务,而子线程则用于执行耗时的后台任务。

Emitter

事件驱动的通信,适合复杂的事件交互。以下是一个简单的 Emitter 使用示例:

import emitter from '@ohos.multimodalInput.event.emitter';
// 创建一个事件发射器
let myEmitter = emitter.createEmitter();
// 监听事件
myEmitter.on('customEvent', (data) => {
    console.log('接收到自定义事件数据:', data);
});
// 触发事件
myEmitter.emit('customEvent', { message: 'Hello from emitter' });

Worker

长时间运行的子线程任务,独立线程,通过消息传递通信。假设要在子线程中进行复杂的计算任务,并将结果返回给主线程:

// worker.js 文件,子线程任务代码
import worker from '@ohos.worker';
worker.onmessage = function (event) {
    let result = performComplexCalculation(event.data);
    worker.postMessage(result);
};
function performComplexCalculation(data) {
    // 模拟复杂计算
    let sum = 0;
    for (let i = 0; i < data; i++) {
        sum += i;
    }
    return sum;
}
// 主线程代码
import worker from '@ohos.worker';
let myWorker = new worker.Worker('worker.js');
myWorker.onmessage = function (event) {
    console.log('子线程计算结果:', event.data);
};
myWorker.postMessage(100);

SharedArrayBuffer

高性能共享数据,需要处理线程同步,适合高性能场景。例如在一个图形处理应用中,多个线程需要共享图像数据:

// 创建共享数组缓冲区
let sharedBuffer = new SharedArrayBuffer(1024);
let view = new Uint8Array(sharedBuffer);
// 线程1 写入数据
let worker1 = new Worker('worker1.js');
worker1.postMessage({ buffer: sharedBuffer, index: 0, data: [1, 2, 3] });
// 线程2 读取数据
let worker2 = new Worker('worker2.js');
worker2.postMessage({ buffer: sharedBuffer });
// worker1.js 代码
import worker from '@ohos.worker';
worker.onmessage = function (event) {
    let { buffer, index, data } = event.data;
    let view = new Uint8Array(buffer);
    data.forEach((value, i) => {
        view[index + i] = value;
    });
};
// worker2.js 代码
import worker from '@ohos.worker';
worker.onmessage = function (event) {
    let { buffer } = event.data;
    let view = new Uint8Array(buffer);
    console.log('读取到的数据:', Array.from(view));
};

线程通讯是确保应用性能和响应性的关键。面试中可能会讨论不同线程通讯机制的实现和最佳实践。