鸿蒙开发中数据总是丢失?本地存储和网络请求搞不定?本文用15分钟带你彻底搞懂Preferences、RDB、HTTP三大数据持久化方案,附完整培训班管理系统实战代码和踩坑记录,让你的鸿蒙App数据存储从此安全可靠!


一、学员信息本地存储

1.1 Preferences轻量级存储

Preferences适用于存储少量键值对数据,如用户配置、登录状态等。

// service/PreferencesHelper.ets
import preferences from '@ohos.data.preferences';

export class PreferencesHelper {
  private static instance: PreferencesHelper;
  private preferencesMap: Map<string, preferences.Preferences> = new Map();

  private constructor() {}

  static getInstance(): PreferencesHelper {
    if (!PreferencesHelper.instance) {
      PreferencesHelper.instance = new PreferencesHelper();
    }
    return PreferencesHelper.instance;
  }

  async getPreferences(context: Context, name: string): Promise<preferences.Preferences> {
    if (this.preferencesMap.has(name)) {
      return this.preferencesMap.get(name)!;
    }

    const prefs = await preferences.getPreferences(context, name);
    this.preferencesMap.set(name, prefs);
    return prefs;
  }

  async put(context: Context, name: string, key: string, value: preferences.ValueType): Promise<void> {
    const prefs = await this.getPreferences(context, name);
    await prefs.put(key, value);
    await prefs.flush();
  }

  async get(context: Context, name: string, key: string, defaultValue: preferences.ValueType): Promise<preferences.ValueType> {
    const prefs = await this.getPreferences(context, name);
    return await prefs.get(key, defaultValue);
  }

  async delete(context: Context, name: string, key: string): Promise<void> {
    const prefs = await this.getPreferences(context, name);
    await prefs.delete(key);
    await prefs.flush();
  }

  async clear(context: Context, name: string): Promise<void> {
    const prefs = await this.getPreferences(context, name);
    await prefs.clear();
    await prefs.flush();
  }
}

1.2 用户配置存储

// service/UserPreferences.ets
import { PreferencesHelper } from './PreferencesHelper';

const PREFS_NAME = 'user_prefs';

export class UserPreferences {
  private static helper: PreferencesHelper = PreferencesHelper.getInstance();

  // 存储用户ID
  static async setUserId(context: Context, userId: string): Promise<void> {
    await this.helper.put(context, PREFS_NAME, 'user_id', userId);
  }

  // 获取用户ID
  static async getUserId(context: Context): Promise<string> {
    return await this.helper.get(context, PREFS_NAME, 'user_id', '') as string;
  }

  // 存储登录状态
  static async setLoginStatus(context: Context, isLoggedIn: boolean): Promise<void> {
    await this.helper.put(context, PREFS_NAME, 'is_logged_in', isLoggedIn);
  }

  // 获取登录状态
  static async getLoginStatus(context: Context): Promise<boolean> {
    return await this.helper.get(context, PREFS_NAME, 'is_logged_in', false) as boolean;
  }

  // 存储用户主题
  static async setTheme(context: Context, theme: string): Promise<void> {
    await this.helper.put(context, PREFS_NAME, 'theme', theme);
  }

  // 获取用户主题
  static async getTheme(context: Context): Promise<string> {
    return await this.helper.get(context, PREFS_NAME, 'theme', 'light') as string;
  }

  // 存储语言设置
  static async setLanguage(context: Context, language: string): Promise<void> {
    await this.helper.put(context, PREFS_NAME, 'language', language);
  }

  // 获取语言设置
  static async getLanguage(context: Context): Promise<string> {
    return await this.helper.get(context, PREFS_NAME, 'language', 'zh_CN') as string;
  }

  // 清除所有用户配置
  static async clearAll(context: Context): Promise<void> {
    await this.helper.clear(context, PREFS_NAME);
  }
}

1.3 使用示例

// pages/SettingsPage.ets
import { UserPreferences } from '../service/UserPreferences';

@Entry
@Component
struct SettingsPage {
  @State theme: string = 'light';
  @State language: string = 'zh_CN';
  @State isLoggedIn: boolean = false;

  async aboutToAppear() {
    this.theme = await UserPreferences.getTheme(this.context);
    this.language = await UserPreferences.getLanguage(this.context);
    this.isLoggedIn = await UserPreferences.getLoginStatus(this.context);
  }

  build() {
    Column() {
      // 标题栏
      TitleBar({ title: '设置', showBack: true })

      List() {
        // 主题设置
        ListItem() {
          this.SettingItem('主题模式', this.theme === 'light' ? '浅色' : '深色', () => {
            this.toggleTheme();
          })
        }

        // 语言设置
        ListItem() {
          this.SettingItem('语言', this.language === 'zh_CN' ? '简体中文' : 'English', () => {
            this.toggleLanguage();
          })
        }

        // 清除数据
        ListItem() {
          this.SettingItem('清除数据', '', () => {
            this.clearData();
          })
        }
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  @Builder
  SettingItem(label: string, value: string, clickCallback: () => void) {
    Row() {
      Text(label)
        .fontSize(16)
        .fontColor('#333333')

      Text(value)
        .fontSize(14)
        .fontColor('#999999')
        .layoutWeight(1)
        .textAlign(TextAlign.End)

      Image($r('app.media.ic_arrow_right'))
        .width(16)
        .height(16)
        .fillColor('#CCCCCC')
    }
    .width('100%')
    .height(56)
    .padding({ left: 16, right: 16 })
    .backgroundColor('#FFFFFF')
    .onClick(clickCallback)
  }

  async toggleTheme() {
    this.theme = this.theme === 'light' ? 'dark' : 'light';
    await UserPreferences.setTheme(this.context, this.theme);
  }

  async toggleLanguage() {
    this.language = this.language === 'zh_CN' ? 'en_US' : 'zh_CN';
    await UserPreferences.setLanguage(this.context, this.language);
  }

  async clearData() {
    // 显示确认弹窗
    AlertDialog.show({
      title: '确认清除',
      message: '确定要清除所有本地数据吗?',
      primaryButton: {
        value: '取消',
        action: () => {}
      },
      secondaryButton: {
        value: '确定',
        action: async () => {
          await UserPreferences.clearAll(this.context);
          Utils.showToast('数据已清除');
        }
      }
    });
  }
}

二、课程数据管理

2.1 关系型数据库(RDB)使用

RDB适用于存储结构化数据,如学员信息、课程信息、报名记录等。

// service/RdbHelper.ets
import rdb from '@ohos.data.relationalStore';

const DB_NAME = 'training_management.db';
const DB_VERSION = 1;

export class RdbHelper {
  private static instance: RdbHelper;
  private rdbStore: rdb.RdbStore | null = null;

  private constructor() {}

  static getInstance(): RdbHelper {
    if (!RdbHelper.instance) {
      RdbHelper.instance = new RdbHelper();
    }
    return RdbHelper.instance;
  }

  async init(context: Context): Promise<void> {
    const config: rdb.StoreConfig = {
      name: DB_NAME,
      securityLevel: rdb.SecurityLevel.S1
    };

    this.rdbStore = await rdb.getRdbStore(context, config, DB_VERSION);
    await this.createTables();
  }

  private async createTables(): Promise<void> {
    // 学员表
    const createStudentTable = `
      CREATE TABLE IF NOT EXISTS student (
        id TEXT PRIMARY KEY,
        name TEXT NOT NULL,
        phone TEXT,
        email TEXT,
        gender INTEGER DEFAULT 0,
        birthday TEXT,
        address TEXT,
        avatar TEXT,
        status INTEGER DEFAULT 0,
        create_time TEXT,
        update_time TEXT
      )
    `;

    // 课程表
    const createCourseTable = `
      CREATE TABLE IF NOT EXISTS course (
        id TEXT PRIMARY KEY,
        name TEXT NOT NULL,
        description TEXT,
        teacher TEXT,
        price REAL,
        duration INTEGER,
        max_students INTEGER,
        current_students INTEGER DEFAULT 0,
        start_time TEXT,
        end_time TEXT,
        status INTEGER DEFAULT 0,
        create_time TEXT,
        update_time TEXT
      )
    `;

    // 报名表
    const createEnrollmentTable = `
      CREATE TABLE IF NOT EXISTS enrollment (
        id TEXT PRIMARY KEY,
        student_id TEXT NOT NULL,
        course_id TEXT NOT NULL,
        enroll_time TEXT,
        status INTEGER DEFAULT 0,
        remark TEXT,
        create_time TEXT,
        update_time TEXT,
        FOREIGN KEY (student_id) REFERENCES student(id),
        FOREIGN KEY (course_id) REFERENCES course(id)
      )
    `;

    await this.rdbStore?.executeSql(createStudentTable);
    await this.rdbStore?.executeSql(createCourseTable);
    await this.rdbStore?.executeSql(createEnrollmentTable);
  }

  getRdbStore(): rdb.RdbStore | null {
    return this.rdbStore;
  }
}

2.2 课程服务实现

// service/CourseService.ets
import { RdbHelper } from './RdbHelper';
import { Course } from '../model/Course';
import rdb from '@ohos.data.relationalStore';

export class CourseService {
  private rdbHelper: RdbHelper = RdbHelper.getInstance();

  // 插入课程
  async insertCourse(course: Course): Promise<void> {
    const rdbStore = this.rdbHelper.getRdbStore();
    if (!rdbStore) return;

    const valueBucket: rdb.ValueBucket = {
      id: course.id,
      name: course.name,
      description: course.description,
      teacher: course.teacher,
      price: course.price,
      duration: course.duration,
      max_students: course.maxStudents,
      current_students: course.currentStudents,
      start_time: course.startTime,
      end_time: course.endTime,
      status: course.status,
      create_time: course.createTime,
      update_time: course.updateTime
    };

    await rdbStore.insert('course', valueBucket);
  }

  // 查询所有课程
  async getAllCourses(): Promise<Course[]> {
    const rdbStore = this.rdbHelper.getRdbStore();
    if (!rdbStore) return [];

    const predicates = new rdb.RdbPredicates('course');
    const resultSet = await rdbStore.query(predicates, [
      'id', 'name', 'description', 'teacher', 'price', 'duration',
      'max_students', 'current_students', 'start_time', 'end_time',
      'status', 'create_time', 'update_time'
    ]);

    const courses: Course[] = [];
    while (resultSet.goToNextRow()) {
      const course: Course = {
        id: resultSet.getString(resultSet.getColumnIndex('id')),
        name: resultSet.getString(resultSet.getColumnIndex('name')),
        description: resultSet.getString(resultSet.getColumnIndex('description')),
        teacher: resultSet.getString(resultSet.getColumnIndex('teacher')),
        price: resultSet.getDouble(resultSet.getColumnIndex('price')),
        duration: resultSet.getInt(resultSet.getColumnIndex('duration')),
        maxStudents: resultSet.getInt(resultSet.getColumnIndex('max_students')),
        currentStudents: resultSet.getInt(resultSet.getColumnIndex('current_students')),
        startTime: resultSet.getString(resultSet.getColumnIndex('start_time')),
        endTime: resultSet.getString(resultSet.getColumnIndex('end_time')),
        status: resultSet.getInt(resultSet.getColumnIndex('status')),
        createTime: resultSet.getString(resultSet.getColumnIndex('create_time')),
        updateTime: resultSet.getString(resultSet.getColumnIndex('update_time'))
      };
      courses.push(course);
    }

    resultSet.close();
    return courses;
  }

  // 根据ID查询课程
  async getCourseById(courseId: string): Promise<Course | null> {
    const rdbStore = this.rdbHelper.getRdbStore();
    if (!rdbStore) return null;

    const predicates = new rdb.RdbPredicates('course');
    predicates.equalTo('id', courseId);
    const resultSet = await rdbStore.query(predicates, [
      'id', 'name', 'description', 'teacher', 'price', 'duration',
      'max_students', 'current_students', 'start_time', 'end_time',
      'status', 'create_time', 'update_time'
    ]);

    if (resultSet.rowCount === 0) {
      resultSet.close();
      return null;
    }

    resultSet.goToNextRow();
    const course: Course = {
      id: resultSet.getString(resultSet.getColumnIndex('id')),
      name: resultSet.getString(resultSet.getColumnIndex('name')),
      description: resultSet.getString(resultSet.getColumnIndex('description')),
      teacher: resultSet.getString(resultSet.getColumnIndex('teacher')),
      price: resultSet.getDouble(resultSet.getColumnIndex('price')),
      duration: resultSet.getInt(resultSet.getColumnIndex('duration')),
      maxStudents: resultSet.getInt(resultSet.getColumnIndex('max_students')),
      currentStudents: resultSet.getInt(resultSet.getColumnIndex('current_students')),
      startTime: resultSet.getString(resultSet.getColumnIndex('start_time')),
      endTime: resultSet.getString(resultSet.getColumnIndex('end_time')),
      status: resultSet.getInt(resultSet.getColumnIndex('status')),
      createTime: resultSet.getString(resultSet.getColumnIndex('create_time')),
      updateTime: resultSet.getString(resultSet.getColumnIndex('update_time'))
    };

    resultSet.close();
    return course;
  }

  // 更新课程
  async updateCourse(course: Course): Promise<void> {
    const rdbStore = this.rdbHelper.getRdbStore();
    if (!rdbStore) return;

    const valueBucket: rdb.ValueBucket = {
      name: course.name,
      description: course.description,
      teacher: course.teacher,
      price: course.price,
      duration: course.duration,
      max_students: course.maxStudents,
      current_students: course.currentStudents,
      start_time: course.startTime,
      end_time: course.endTime,
      status: course.status,
      update_time: Utils.formatDate(new Date())
    };

    const predicates = new rdb.RdbPredicates('course');
    predicates.equalTo('id', course.id);
    await rdbStore.update(valueBucket, predicates);
  }

  // 删除课程
  async deleteCourse(courseId: string): Promise<void> {
    const rdbStore = this.rdbHelper.getRdbStore();
    if (!rdbStore) return;

    const predicates = new rdb.RdbPredicates('course');
    predicates.equalTo('id', courseId);
    await rdbStore.delete(predicates);
  }

  // 搜索课程
  async searchCourses(keyword: string): Promise<Course[]> {
    const rdbStore = this.rdbHelper.getRdbStore();
    if (!rdbStore) return [];

    const predicates = new rdb.RdbPredicates('course');
    predicates.like('name', `%${keyword}%`);
    const resultSet = await rdbStore.query(predicates, [
      'id', 'name', 'description', 'teacher', 'price', 'duration',
      'max_students', 'current_students', 'start_time', 'end_time',
      'status', 'create_time', 'update_time'
    ]);

    const courses: Course[] = [];
    while (resultSet.goToNextRow()) {
      const course: Course = {
        id: resultSet.getString(resultSet.getColumnIndex('id')),
        name: resultSet.getString(resultSet.getColumnIndex('name')),
        description: resultSet.getString(resultSet.getColumnIndex('description')),
        teacher: resultSet.getString(resultSet.getColumnIndex('teacher')),
        price: resultSet.getDouble(resultSet.getColumnIndex('price')),
        duration: resultSet.getInt(resultSet.getColumnIndex('duration')),
        maxStudents: resultSet.getInt(resultSet.getColumnIndex('max_students')),
        currentStudents: resultSet.getInt(resultSet.getColumnIndex('current_students')),
        startTime: resultSet.getString(resultSet.getColumnIndex('start_time')),
        endTime: resultSet.getString(resultSet.getColumnIndex('end_time')),
        status: resultSet.getInt(resultSet.getColumnIndex('status')),
        createTime: resultSet.getString(resultSet.getColumnIndex('create_time')),
        updateTime: resultSet.getString(resultSet.getColumnIndex('update_time'))
      };
      courses.push(course);
    }

    resultSet.close();
    return courses;
  }

  // 获取课程统计
  async getCourseStats(): Promise<{ total: number; inProgress: number; ended: number }> {
    const rdbStore = this.rdbHelper.getRdbStore();
    if (!rdbStore) return { total: 0, inProgress: 0, ended: 0 };

    const totalResult = await rdbStore.querySql('SELECT COUNT(*) as count FROM course');
    totalResult.goToNextRow();
    const total = totalResult.getInt(0);
    totalResult.close();

    const inProgressResult = await rdbStore.querySql('SELECT COUNT(*) as count FROM course WHERE status = 1');
    inProgressResult.goToNextRow();
    const inProgress = inProgressResult.getInt(0);
    inProgressResult.close();

    const endedResult = await rdbStore.querySql('SELECT COUNT(*) as count FROM course WHERE status = 2');
    endedResult.goToNextRow();
    const ended = endedResult.getInt(0);
    endedResult.close();

    return { total, inProgress, ended };
  }
}

三、网络请求与API对接

3.1 HTTP请求封装

// service/HttpHelper.ets
import http from '@ohos.net.http';

export class HttpHelper {
  private static baseUrl: string = 'https://api.example.com';

  static async get<T>(path: string, params?: Record<string, string>): Promise<T> {
    const url = this.buildUrl(path, params);
    const httpRequest = http.createHttp();

    try {
      const response = await httpRequest.request(url, {
        method: http.RequestMethod.GET,
        header: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${await this.getToken()}`
        }
      });

      if (response.responseCode === 200) {
        return JSON.parse(response.result as string) as T;
      } else {
        throw new Error(`HTTP Error: ${response.responseCode}`);
      }
    } finally {
      httpRequest.destroy();
    }
  }

  static async post<T>(path: string, data: Record<string, any>): Promise<T> {
    const url = this.buildUrl(path);
    const httpRequest = http.createHttp();

    try {
      const response = await httpRequest.request(url, {
        method: http.RequestMethod.POST,
        header: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${await this.getToken()}`
        },
        extraData: JSON.stringify(data)
      });

      if (response.responseCode === 200) {
        return JSON.parse(response.result as string) as T;
      } else {
        throw new Error(`HTTP Error: ${response.responseCode}`);
      }
    } finally {
      httpRequest.destroy();
    }
  }

  static async put<T>(path: string, data: Record<string, any>): Promise<T> {
    const url = this.buildUrl(path);
    const httpRequest = http.createHttp();

    try {
      const response = await httpRequest.request(url, {
        method: http.RequestMethod.PUT,
        header: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${await this.getToken()}`
        },
        extraData: JSON.stringify(data)
      });

      if (response.responseCode === 200) {
        return JSON.parse(response.result as string) as T;
      } else {
        throw new Error(`HTTP Error: ${response.responseCode}`);
      }
    } finally {
      httpRequest.destroy();
    }
  }

  static async delete<T>(path: string): Promise<T> {
    const url = this.buildUrl(path);
    const httpRequest = http.createHttp();

    try {
      const response = await httpRequest.request(url, {
        method: http.RequestMethod.DELETE,
        header: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${await this.getToken()}`
        }
      });

      if (response.responseCode === 200) {
        return JSON.parse(response.result as string) as T;
      } else {
        throw new Error(`HTTP Error: ${response.responseCode}`);
      }
    } finally {
      httpRequest.destroy();
    }
  }

  private static buildUrl(path: string, params?: Record<string, string>): string {
    let url = `${this.baseUrl}${path}`;
    if (params) {
      const queryString = Object.entries(params)
        .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
        .join('&');
      url += `?${queryString}`;
    }
    return url;
  }

  private static async getToken(): Promise<string> {
    // 从本地存储获取token
    return await UserPreferences.getToken();
  }
}

3.2 API服务封装

// service/ApiService.ets
import { HttpHelper } from './HttpHelper';

export interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

export class ApiService {
  // 获取课程列表
  static async getCourses(): Promise<Course[]> {
    const response = await HttpHelper.get<ApiResponse<Course[]>>('/courses');
    return response.data;
  }

  // 获取课程详情
  static async getCourseDetail(courseId: string): Promise<Course> {
    const response = await HttpHelper.get<ApiResponse<Course>>(`/courses/${courseId}`);
    return response.data;
  }

  // 创建课程
  static async createCourse(course: Course): Promise<Course> {
    const response = await HttpHelper.post<ApiResponse<Course>>('/courses', course);
    return response.data;
  }

  // 更新课程
  static async updateCourse(courseId: string, course: Course): Promise<Course> {
    const response = await HttpHelper.put<ApiResponse<Course>>(`/courses/${courseId}`, course);
    return response.data;
  }

  // 删除课程
  static async deleteCourse(courseId: string): Promise<void> {
    await HttpHelper.delete<ApiResponse<void>>(`/courses/${courseId}`);
  }

  // 获取学员列表
  static async getStudents(): Promise<Student[]> {
    const response = await HttpHelper.get<ApiResponse<Student[]>>('/students');
    return response.data;
  }

  // 创建报名
  static async createEnrollment(enrollment: Enrollment): Promise<Enrollment> {
    const response = await HttpHelper.post<ApiResponse<Enrollment>>('/enrollments', enrollment);
    return response.data;
  }
}

四、数据缓存策略

4.1 缓存管理器

// service/CacheManager.ets
export class CacheManager {
  private static cache: Map<string, { data: any; timestamp: number }> = new Map();
  private static CACHE_DURATION = 5 * 60 * 1000; // 5分钟缓存

  static set(key: string, data: any): void {
    this.cache.set(key, {
      data: data,
      timestamp: Date.now()
    });
  }

  static get<T>(key: string): T | null {
    const cached = this.cache.get(key);
    if (!cached) return null;

    const isExpired = Date.now() - cached.timestamp > this.CACHE_DURATION;
    if (isExpired) {
      this.cache.delete(key);
      return null;
    }

    return cached.data as T;
  }

  static has(key: string): boolean {
    const cached = this.cache.get(key);
    if (!cached) return false;

    const isExpired = Date.now() - cached.timestamp > this.CACHE_DURATION;
    if (isExpired) {
      this.cache.delete(key);
      return false;
    }

    return true;
  }

  static delete(key: string): void {
    this.cache.delete(key);
  }

  static clear(): void {
    this.cache.clear();
  }
}

4.2 带缓存的数据服务

// service/CachedCourseService.ets
import { CacheManager } from './CacheManager';

export class CachedCourseService {
  private static CACHE_KEY_ALL_COURSES = 'all_courses';
  private static courseService: CourseService = new CourseService();

  static async getAllCourses(): Promise<Course[]> {
    // 先从缓存获取
    const cached = CacheManager.get<Course[]>(this.CACHE_KEY_ALL_COURSES);
    if (cached) {
      return cached;
    }

    // 缓存未命中,从数据库获取
    const courses = await this.courseService.getAllCourses();

    // 存入缓存
    CacheManager.set(this.CACHE_KEY_ALL_COURSES, courses);

    return courses;
  }

  static async getCourseById(courseId: string): Promise<Course | null> {
    const cacheKey = `course_${courseId}`;

    // 先从缓存获取
    const cached = CacheManager.get<Course>(cacheKey);
    if (cached) {
      return cached;
    }

    // 缓存未命中,从数据库获取
    const course = await this.courseService.getCourseById(courseId);
    if (course) {
      CacheManager.set(cacheKey, course);
    }

    return course;
  }

  static async insertCourse(course: Course): Promise<void> {
    await this.courseService.insertCourse(course);
    // 清除相关缓存
    CacheManager.delete(this.CACHE_KEY_ALL_COURSES);
  }

  static async updateCourse(course: Course): Promise<void> {
    await this.courseService.updateCourse(course);
    // 清除相关缓存
    CacheManager.delete(this.CACHE_KEY_ALL_COURSES);
    CacheManager.delete(`course_${course.id}`);
  }

  static async deleteCourse(courseId: string): Promise<void> {
    await this.courseService.deleteCourse(courseId);
    // 清除相关缓存
    CacheManager.delete(this.CACHE_KEY_ALL_COURSES);
    CacheManager.delete(`course_${courseId}`);
  }
}

五、离线功能实现

5.1 离线数据同步

// service/OfflineSyncService.ets
export class OfflineSyncService {
  private static pendingOperations: Array<{
    type: 'create' | 'update' | 'delete';
    table: string;
    data: any;
    timestamp: number;
  }> = [];

  // 添加待同步操作
  static addPendingOperation(
    type: 'create' | 'update' | 'delete',
    table: string,
    data: any
  ): void {
    this.pendingOperations.push({
      type,
      table,
      data,
      timestamp: Date.now()
    });

    // 保存到本地存储
    this.savePendingOperations();
  }

  // 同步待处理操作
  static async syncPendingOperations(): Promise<void> {
    const operations = [...this.pendingOperations];

    for (const operation of operations) {
      try {
        await this.executeOperation(operation);
        // 成功后移除
        this.pendingOperations = this.pendingOperations.filter(
          op => op.timestamp !== operation.timestamp
        );
      } catch (error) {
        console.error('同步操作失败:', error);
        break;
      }
    }

    // 保存更新后的待处理操作
    this.savePendingOperations();
  }

  private static async executeOperation(operation: any): Promise<void> {
    switch (operation.type) {
      case 'create':
        await this.executeCreate(operation.table, operation.data);
        break;
      case 'update':
        await this.executeUpdate(operation.table, operation.data);
        break;
      case 'delete':
        await this.executeDelete(operation.table, operation.data);
        break;
    }
  }

  private static async executeCreate(table: string, data: any): Promise<void> {
    switch (table) {
      case 'courses':
        await ApiService.createCourse(data);
        break;
      case 'students':
        await ApiService.createStudent(data);
        break;
      case 'enrollments':
        await ApiService.createEnrollment(data);
        break;
    }
  }

  private static async executeUpdate(table: string, data: any): Promise<void> {
    switch (table) {
      case 'courses':
        await ApiService.updateCourse(data.id, data);
        break;
      case 'students':
        await ApiService.updateStudent(data.id, data);
        break;
    }
  }

  private static async executeDelete(table: string, data: any): Promise<void> {
    switch (table) {
      case 'courses':
        await ApiService.deleteCourse(data.id);
        break;
      case 'students':
        await ApiService.deleteStudent(data.id);
        break;
    }
  }

  private static savePendingOperations(): void {
    // 保存到Preferences
    const operationsJson = JSON.stringify(this.pendingOperations);
    // 实际实现中需要调用Preferences保存
  }

  static loadPendingOperations(): void {
    // 从Preferences加载
    // 实际实现中需要调用Preferences读取
    this.pendingOperations = [];
  }

  static getPendingOperationsCount(): number {
    return this.pendingOperations.length;
  }
}

5.2 网络状态监听

// service/NetworkMonitor.ets
import { connection } from '@kit.NetworkKit';

export class NetworkMonitor {
  private static isOnline: boolean = true;
  private static listeners: Array<(isOnline: boolean) => void> = [];

  static async init(): Promise<void> {
    // 获取初始网络状态
    try {
      const netConn = connection.createNetConnection();
      const netCapabilities = await netConn.getNetCapabilities();
      this.isOnline = netCapabilities.linkUp && netCapabilities.linkAddresses.length > 0;
    } catch (error) {
      console.error('获取网络状态失败:', error);
    }

    // 监听网络变化
    connection.on('netAvailable', () => {
      this.isOnline = true;
      this.notifyListeners();
    });

    connection.on('netUnavailable', () => {
      this.isOnline = false;
      this.notifyListeners();
    });
  }

  static getIsOnline(): boolean {
    return this.isOnline;
  }

  static addListener(listener: (isOnline: boolean) => void): void {
    this.listeners.push(listener);
  }

  static removeListener(listener: (isOnline: boolean) => void): void {
    this.listeners = this.listeners.filter(l => l !== listener);
  }

  private static notifyListeners(): void {
    this.listeners.forEach(listener => {
      listener(this.isOnline);
    });
  }
}

六、踩坑记录

6.1 Preferences数据丢失

问题:应用更新后Preferences数据丢失。

原因:应用签名变更导致Preferences文件被清除。

解决方案

// 使用RDB存储重要数据,Preferences仅存储临时配置
// 或者在应用更新时迁移数据

6.2 RDB并发访问问题

问题:多线程同时访问RDB导致异常。

原因:RDB不支持并发写入。

解决方案

// 使用队列串行化数据库操作
private operationQueue: Array<() => Promise<void>> = [];
private isProcessing: boolean = false;

async enqueueOperation(operation: () => Promise<void>): Promise<void> {
  this.operationQueue.push(operation);
  if (!this.isProcessing) {
    await this.processQueue();
  }
}

private async processQueue(): Promise<void> {
  this.isProcessing = true;
  while (this.operationQueue.length > 0) {
    const operation = this.operationQueue.shift();
    if (operation) {
      await operation();
    }
  }
  this.isProcessing = false;
}

6.3 HTTP请求超时

问题:网络不稳定时请求超时。

原因:未设置合理的超时时间。

解决方案

// 设置请求超时
const response = await httpRequest.request(url, {
  method: http.RequestMethod.GET,
  connectTimeout: 10000, // 10秒连接超时
  readTimeout: 30000,    // 30秒读取超时
  header: {
    'Content-Type': 'application/json'
  }
});

七、总结与预告

本文要点回顾

  1. Preferences:轻量级键值对存储,适用于配置数据

  2. RDB:关系型数据库,适用于结构化数据

  3. HTTP请求:网络API封装,支持RESTful接口

  4. 数据缓存:内存缓存策略,提升访问性能

  5. 离线功能:离线数据同步,保证数据一致性

下期预告

下期我们将深入讲解性能优化篇,包括:

  • 学员列表性能优化

  • 图片加载与缓存优化

  • 启动速度优化

  • 内存管理与泄漏检测

互动引导

如果本文对你有帮助,请点赞、收藏、关注!有任何问题欢迎在评论区留言,我会及时回复。


系列文章导航

  • 第1篇:项目架构篇

  • 第2篇:UI界面篇

  • 第3篇:状态管理篇

  • 第4篇:数据持久化篇(本文)

  • 第5篇:性能优化篇

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐