跳至主要內容

第9次课

周子力大约 7 分钟教学文档HarmonyOS

课前回顾

1.数据持久化,比如在备忘录应用中,当用户添加、删除、修改了数据时,数据需要持久化到本地。

2.preference的使用,比如在备忘录应用中,用户设置主题色时,需要保存到本地。

在鸿蒙(HarmonyOS)应用开发中,Preference首选项是一种轻量级的数据持久化存储方案,主要用于存储少量、简单的键值对数据。以下是关于Preference首选项的详细阐述:

1. Preference首选项概述

Preference是一种基于键值对(Key-Value)的轻量级存储机制,适用于保存应用的配置信息、用户设置等小规模数据。

特点:

  • 数据以XML文件形式存储
  • 线程安全,支持异步操作
  • 存储简单数据类型
  • 自动持久化到设备存储

2. 基本使用方法

2.1 获取Preference实例

import preferences from '@ohos.data.preferences';

// 获取Preference实例
let preferences: Promise<preferences.Preferences> = preferences.getPreferences(this.context, 'myAppPrefs');

2.2 存储数据

async function saveData() {
  try {
    let pref = await preferences.getPreferences(this.context, 'myAppPrefs');
    
    // 存储不同类型的数据
    await pref.put('username', '张三');
    await pref.put('age', 25);
    await pref.put('isLoggedIn', true);
    await pref.put('score', 95.5);
    
    // 提交保存
    await pref.flush();
    console.log('数据保存成功');
  } catch (err) {
    console.error('保存数据失败: ' + err);
  }
}

2.3 读取数据

async function readData() {
  try {
    let pref = await preferences.getPreferences(this.context, 'myAppPrefs');
    
    // 读取数据,第二个参数为默认值
    let username = await pref.get('username', '默认用户');
    let age = await pref.get('age', 0);
    let isLoggedIn = await pref.get('isLoggedIn', false);
    let score = await pref.get('score', 0.0);
    
    console.log(`用户名: ${username}`);
    console.log(`年龄: ${age}`);
    console.log(`登录状态: ${isLoggedIn}`);
    console.log(`分数: ${score}`);
  } catch (err) {
    console.error('读取数据失败: ' + err);
  }
}

3. 完整示例代码

import preferences from '@ohos.data.preferences';

export default class PreferenceUtils {
  private static PREF_NAME = 'myAppPreferences';
  
  // 保存用户信息
  static async saveUserInfo(userInfo: UserInfo) {
    try {
      let pref = await preferences.getPreferences(getContext(), this.PREF_NAME);
      
      await pref.put('userId', userInfo.id);
      await pref.put('userName', userInfo.name);
      await pref.put('userEmail', userInfo.email);
      await pref.put('loginTime', Date.now());
      await pref.put('rememberMe', userInfo.rememberMe);
      
      await pref.flush();
      console.log('用户信息保存成功');
    } catch (err) {
      console.error('保存用户信息失败: ' + err);
    }
  }
  
  // 读取用户信息
  static async getUserInfo(): Promise<UserInfo> {
    try {
      let pref = await preferences.getPreferences(getContext(), this.PREF_NAME);
      
      return {
        id: await pref.get('userId', ''),
        name: await pref.get('userName', ''),
        email: await pref.get('userEmail', ''),
        loginTime: await pref.get('loginTime', 0),
        rememberMe: await pref.get('rememberMe', false)
      };
    } catch (err) {
      console.error('读取用户信息失败: ' + err);
      return new UserInfo();
    }
  }
  
  // 删除指定数据
  static async deleteKey(key: string) {
    try {
      let pref = await preferences.getPreferences(getContext(), this.PREF_NAME);
      await pref.delete(key);
      await pref.flush();
    } catch (err) {
      console.error('删除数据失败: ' + err);
    }
  }
  
  // 清空所有数据
  static async clearAll() {
    try {
      let pref = await preferences.getPreferences(getContext(), this.PREF_NAME);
      await pref.clear();
      await pref.flush();
    } catch (err) {
      console.error('清空数据失败: ' + err);
    }
  }
}

class UserInfo {
  id: string = '';
  name: string = '';
  email: string = '';
  loginTime: number = 0;
  rememberMe: boolean = false;
}

4. 高级用法

4.1 数据变更监听

async function setupPreferenceListener() {
  try {
    let pref = await preferences.getPreferences(this.context, 'myAppPrefs');
    
    // 添加数据变更监听器
    pref.on('change', (key: string) => {
      console.log(`数据发生变化: ${key}`);
      // 执行相应的业务逻辑
    });
  } catch (err) {
    console.error('设置监听器失败: ' + err);
  }
}

4.2 多Preference文件管理

class MultiPreferenceManager {
  private static USER_PREF = 'user_preferences';
  private static APP_PREF = 'app_preferences';
  private static CACHE_PREF = 'cache_preferences';
  
  // 获取不同的Preference文件
  static async getUserPreferences() {
    return await preferences.getPreferences(getContext(), this.USER_PREF);
  }
  
  static async getAppPreferences() {
    return await preferences.getPreferences(getContext(), this.APP_PREF);
  }
  
  static async getCachePreferences() {
    return await preferences.getPreferences(getContext(), this.CACHE_PREF);
  }
}

5. 最佳实践

5.1 封装工具类

export class PreferenceHelper {
  private prefName: string;
  
  constructor(prefName: string) {
    this.prefName = prefName;
  }
  
  // 安全地保存数据
  async safePut(key: string, value: preferences.ValueType): Promise<boolean> {
    try {
      let pref = await preferences.getPreferences(getContext(), this.prefName);
      await pref.put(key, value);
      await pref.flush();
      return true;
    } catch (err) {
      console.error(`保存数据失败 key:${key}`, err);
      return false;
    }
  }
  
  // 安全地读取数据
  async safeGet<T extends preferences.ValueType>(key: string, defaultValue: T): Promise<T> {
    try {
      let pref = await preferences.getPreferences(getContext(), this.prefName);
      return await pref.get(key, defaultValue) as T;
    } catch (err) {
      console.error(`读取数据失败 key:${key}`, err);
      return defaultValue;
    }
  }
}

// 使用示例
const appPrefs = new PreferenceHelper('app_settings');
await appPrefs.safePut('theme', 'dark');
let theme = await appPrefs.safeGet('theme', 'light');

6. 适用场景

  • 适合:用户设置、应用配置、登录状态、简单的用户数据
  • 不适合:大量结构化数据、复杂查询、关系型数据

总结

Preference首选项是鸿蒙应用开发中最简单易用的数据持久化方案,适合存储小规模的配置数据和用户偏好设置。通过合理的封装和错误处理,可以构建稳定可靠的数据存储逻辑。

本周内容

在鸿蒙(HarmonyOS)应用开发中,axios 是一个基于 Promise 的网络请求库,它可以帮助你更简洁、高效地处理 HTTP 请求 。下面我将为你介绍如何在鸿蒙项目中安装、配置和使用 axios

🔧 安装与基础配置

在鸿蒙项目中使用 axios 前,你需要先完成安装和权限配置。

  1. 安装 Axios 在鸿蒙项目的根目录下,通过以下命令使用 OpenHarmony Package Manager (ohpm) 进行安装 :

    ohpm install @ohos/axios
    
  2. 配置网络权限 为了应用能够访问网络,你需要在 module.json5 文件中声明网络权限 。

    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
    

🚀 发起网络请求

安装和配置完成后,你就可以开始使用 axios 发起网络请求了。

  1. 引入 Axios 在使用 axios 的页面或工具文件中,首先需要引入它 :

    import axios from '@ohos/axios';
    
  2. 发起 GET 请求 使用 axios.get 方法发起 GET 请求 :

    axios.get('https://api.example.com/data')
      .then(response => {
        // 请求成功,处理响应数据
        console.log(response.data);
      })
      .catch(error => {
        // 请求失败,处理错误
        console.error(error);
      });
    
  3. 发起 POST 请求 使用 axios.post 方法发起 POST 请求 :

    axios.post('https://api.example.com/submit', { name: 'Alice', age: 30 })
      .then(response => {
        console.log('Submit Success:', response.data);
      })
      .catch(error => {
        console.error('Request Failed:', error);
      });
    

💡 进阶用法与最佳实践

为了在大型项目中更好地管理网络请求,建议进行更完善的封装和配置。

  1. 创建 Axios 实例 你可以创建一个配置好的 Axios 实例,设置公共的基路径(baseURL)和超时时间 :

    const instance = axios.create({
      baseURL: 'https://api.yourdomain.com', // 你的接口基地址
      timeout: 60000 // 超时时间,单位毫秒
    });
    
  2. 使用请求和响应拦截器 拦截器让你能在请求发出前或响应返回后,进行统一的预处理,例如自动添加身份验证令牌(Token)或统一处理错误 。

    请求拦截器示例:

    instance.interceptors.request.use((config) => {
      // 在发送请求前做些什么,例如添加token
      const token = '...'; // 从本地获取token的逻辑
      if (token) {
        config.headers.token = token; // 将token添加到请求头
      }
      return config;
    }, (error) => {
      // 对请求错误做些什么
      return Promise.reject(error);
    });
    

    响应拦截器示例:

    instance.interceptors.response.use((response: AxiosResponse) => {
      // 对响应数据做点什么,例如根据业务代码统一处理
      let data = response.data;
      if (data.code === 200) {
        return data; // 业务成功,返回数据
      } else {
        // 业务异常,可以在此显示Toast提示
        console.error('Request failed with message:', data.msg);
        return Promise.reject(new Error(data.msg));
      }
    }, (error) => {
      // 对响应错误做点什么,例如处理HTTP状态码非200的情况
      console.error('Network error:', error);
      return Promise.reject(error);
    });
    
  3. 对请求参数和响应数据进行类型约束 在 ArkTS 中,推荐使用泛型来定义请求参数和响应数据的类型,以获得更好的类型安全和代码提示 。

    定义接口

    // 定义请求参数类型
    interface LoginRequest {
      phone: string;
      passwd: string;
    }
    
    // 定义响应数据类型
    interface LoginResponse {
      code: number;
      msg: string;
      token: string;
    }
    

    在请求中使用泛型

    // 在post请求中,三个泛型参数依次为:响应数据类型、AxiosResponse类型、请求参数类型
    const response = await instance.post<LoginResponse, AxiosResponse<LoginResponse, null>, LoginRequest>('/user/login', {
      phone: '13166666666',
      passwd: 'yourpassword'
    });
    console.log(response.token); // 此时有类型提示
    

💎 封装与实践建议

  • 封装工具类:建议将 axios 实例和通用配置封装成一个独立的工具类(如 BaseRequest),方便在整个项目中统一管理和使用 。
  • 结合业务逻辑:根据后端接口返回的数据结构,封装通用的响应类型,并抽取通用的请求方法,避免重复代码 。

axios 通过其简洁的 API、强大的拦截器机制和良好的类型支持,能够显著提升鸿蒙应用开发中网络请求的效率与可维护性 。希望这些信息能帮助你快速上手!如果你对特定场景下的使用方法有更多疑问,欢迎随时提出。

上次编辑于:
贡献者: zilizhou