HarmonyOS应用开发-首选项与后台通知管理

首选项

在移动互联网蓬勃发展的今天,移动应用给我们生活带来了极大的便利,这些便利的本质在于数据的互联互通。因此在应用的开发中数据存储占据了非常重要的位置,HarmonyOS应用开发也不例外。本章以HarmonyOS的首选项为例,介绍了HarmonyOS的数据管理能力。

什么是首选项

首选项为应用提供Key-Value键值型的数据存储能力,支持应用持久化轻量级数据,并对其进行增删除改查等。该存储对象中的数据会被缓存在内存中,因此它可以获得更快的存取速度。

首选项的特点如下:

  1. Key-Value形式存储数据: 数据以键值对的形式存储,其中Key是唯一的关键字,而对应的Value是实际的数据值。

  2. 非关系型数据库: 与关系型数据库不同,首选项不遵循ACID特性(Atomicity, Consistency, Isolation, Durability),且数据之间没有关系。

  3. 进程中的唯一实例: 在一个进程中,每个文件只存在一个首选项实例。应用程序获取到该实例后,可以从中读取数据或将数据存入其中。通过调用flush方法,可以将实例中的数据回写到文件中。

  4. 与关系数据库的区别:

    特点/属性 关系数据库 首选项
    数据存储形式 表格(关系) Key-Value(非关系型)
    ACID特性 遵循ACID 不遵循ACID
    数据关系 数据表之间存在关联关系 无数据关系,独立的Key-Value对
    存储引擎 使用数据库引擎,如SQLite等 存储在文件中
    使用场景 复杂场景下的本地数据库管理 对Key-Value结构的数据进行简单操作
    数据处理 复杂查询、事务处理等 简单的存取和持久化操作
    约束和限制 连接池大小、同时写操作数等 数据条目数量建议、Key类型限制

首选项常用接口

接口 功能
put 将数据存储到首选项中
get 通过指定的Key获取首选项中的数据值
has 检查首选项中是否包含给定的Key
delete 从首选项中删除指定Key的数据
flush 将首选项中的数据写回到文件中,实现数据持久化

在使用前需要导入@ohos.data.preferences模块,实例名字命名为dataPreferences,同时定义两个常量PREFERENCES_NAME和KEY_APP_FONT_SIZE。

// PreferencesUtil.ets
import dataPreferences from '@ohos.data.preferences';
   ...
  const PREFERENCES_NAME = 'myPreferences'; // 首选项名字
  const KEY_APP_FONT_SIZE = 'appFontSize';  // 首选项Key字段

需要在entryAbility的onCreate方法获取首选项实例,以便后续能进行保存、读取、删除等操作,获取实例需要上下文context和文件名字PREFERENCES_NAME

// entryAbility.ets  
  onCreate(want, launchParam) {
    Logger.info(TAG, 'onCreate');
    globalThis.abilityWant = want;
    // 创建首选项
    PreferencesUtil.createFontPreferences(this.context);
    ...
  }

// PreferencesUtil.ets  
  createFontPreferences(context) {
    globalThis.getFontPreferences = (() => {
      // 获取首选项实例
      let preferences: Promise<dataPreferences.Preferences> = dataPreferences.getPreferences(context, PREFERENCES_NAME);
      return preferences;
    });
  }

保存数据

在entryAbility的onCreate方法,调用PreferencesUtil.saveDefaultFontSize保存默认数据,先用has方法判断当前key是否有存在,如果没有就通过put方法把用户数据保存起来,该方法通过key-value键值对方式保存,常量KEY_APP_FONT_SIZE作为key,用户数据fontSize作为value,再通过flush方法把数据保存到文件。

// entryAbility.ets  
  onCreate(want, launchParam) {
    Logger.info(TAG, 'onCreate');
    globalThis.abilityWant = want;
    ...
    // 设置字体默认大小
    PreferencesUtil.saveDefaultFontSize(Constants.SET_SIZE_STANDARD);
  }
// PreferencesUtil.ets    
  saveDefaultFontSize(fontSize: number) {
    globalThis.getFontPreferences().then((preferences) => {
      // 判断保存的key是否存在
      preferences.has(KEY_APP_FONT_SIZE).then(async (isExist) => {
        Logger.info(TAG, 'preferences has changeFontSize is ' + isExist);
        if (!isExist) {
          // 保存数据
          await preferences.put(KEY_APP_FONT_SIZE, fontSize);
          preferences.flush();
        }
      }).catch((err) => {
        Logger.error(TAG, 'Has the value failed with err: ' + err);
      });
    }).catch((err) => {
      Logger.error(TAG, 'Get the preferences failed, err: ' + err);
    });
  }

获取数据

在HomePage的onPageShow方法,调用PreferencesUtil.getChangeFontSize方法获取用户数据,调用get方法获取,该方法通过key-value键值对方式读取,常量KEY_APP_FONT_SIZE作为key,默认数据fontSize作为value,把的到的结果赋值给变量fontSize,通过return方式把值返回去。

// HomePage.ets
  onPageShow() {
    PreferencesUtil.getChangeFontSize().then((value) => {
      this.changeFontSize = value;
      Logger.info(TAG, 'Get the value of changeFontSize: ' + this.changeFontSize);
    });
  }
// PreferencesUtil.ets 
  async getChangeFontSize() {
    let fontSize: number = 0;
    const preferences = await globalThis.getFontPreferences();
    fontSize = await preferences.get(KEY_APP_FONT_SIZE, fontSize);
    return fontSize;
  }

是否包含指定的key

通过has方法判断首选项中是否包含指定的key,保证指定的key不会被重复保存。

// PreferencesUtil.ets    
  saveDefaultFontSize(fontSize: number) {
    globalThis.getFontPreferences().then((preferences) => {
      // 判断保存的key是否存在
      preferences.has(KEY_APP_FONT_SIZE).then(async (isExist) => {
        Logger.info(TAG, 'preferences has changeFontSize is ' + isExist);
      }).catch((err) => {
        Logger.error(TAG, 'Has the value failed with err: ' + err);
      });
    }).catch((err) => {
      Logger.error(TAG, 'Get the preferences failed, err: ' + err);
    });
  }

数据持久化

通过flush方法把应用数据保存到文件中,使得应用数据保存期限变长

// PreferencesUtil.ets 
  saveChangeFontSize(fontSize: number) {
    globalThis.getFontPreferences().then(async (preferences) => {
      // 保存数据
      await preferences.put(KEY_APP_FONT_SIZE, fontSize);
     // 数据持久化
      preferences.flush();
    }).catch((err) => {
      Logger.error(TAG, 'put the preferences failed, err: ' + err);
    });
  }

删除数据

删除首选项数据需要获取preferences实例,用delete方法删除指定的key所对应的值,常量KEY_APP_FONT_SIZE作为key,通过Promise异步回调是否删除成功。

// PreferencesUtil.ets 
  async deleteChangeFontSize() {
    const preferences: dataPreferences.Preferences = await globalThis.getFontPreferences();
    // 删除数据
    let deleteValue = preferences.delete(KEY_APP_FONT_SIZE);
    deleteValue.then(() => {
      Logger.info(TAG, 'Succeeded in deleting the key appFontSize.');
    }).catch((err) => {
      Logger.error(TAG, 'Failed to delete the key appFontSize. Cause: ' + err);
    });
  }

后台通知管理

通知的作用

通知旨在让用户以合适的方式及时获得有用的新消息,帮助用户高效地处理任务。应用可以通过通知接口发送通知消息,用户可以通过通知栏查看通知内容,也可以点击通知来打开应用,通知主要有以下使用场景:

  • 显示接收到的短消息、即时消息等。
  • 显示应用的推送消息,如广告、版本更新等。
  • 显示当前正在进行的事件,如下载等。

通知会在不同场景以不同形式提示用户,例如通知在状态栏上显示为图标、在通知栏上会显示通知详细信息。重要的信息还可以使用横幅通知,浮动在界面顶部显示。

创建通知

本节将介绍几种常见类型通知的创建,在创建通知前需要先导入notificationManager模块,该模块提供通知管理的能力,包括发布、取消发布通知,创建、获取、移除通知通道等能力。

import notification from '@ohos.notificationManager';

基础类型通知

基础类型通知主要应用于发送短信息提示信息广告推送等,支持普通文本类型、长文本类型、多行文本类型和图片类型,可以通过contentType指定通知的内容类型。

发布普通文本类型通知,需要设置contentType类型为ContentType.NOTIFICATION_CONTENT_BASIC_TEXT

import notification from '@ohos.notificationManager';

@Entry
@Component
struct NotificationDemo {
  publishNotification() {
    let notificationRequest: notification.NotificationRequest = { // 描述通知的请求
      id: 1, // 通知ID
      slotType: notification.SlotType.SERVICE_INFORMATION,
      content: { // 通知内容
        contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, // 普通文本类型通知
        normal: { // 基本类型通知内容
          title: '通知内容标题',
          text: '通知内容详情',
          additionalText: '通知附加内容', // 通知附加内容,是对通知内容的补充。
        }
      }
    }
    notification.publish(notificationRequest).then(() => { // 发布通知
      console.info('publish success');
    }).catch((err) => {
      console.error(`publish failed, dcode:${err.code}, message:${err.message}`);
    });
  }

  build() {
    Column() {
      Button('发送通知')
        .onClick(() => {
          this.publishNotification()
        })
    }
    .width('100%')
  }
}
参数名 作用
notificationRequest 描述通知的请求对象,包含通知的各种信息。
id 通知的唯一标识符,用于区分不同的通知。
slotType 通知的槽类型,指定通知在通知栏的位置。
content 包含通知内容的对象,指定通知的类型和具体内容。
contentType 指定通知的内容类型,例如普通文本、长文本、图片等。
normal 包含普通文本类型通知的具体内容信息。
title 普通文本类型通知的标题。
text 普通文本类型通知的详细内容。
additionalText 普通文本类型通知的附加内容,对通知内容的补充说明。
publish notification.publish方法,用于发布通知。
then Promise的成功回调,用于在通知发布成功后执行的操作。
catch Promise的失败回调,用于在通知发布失败时处理错误情况。
onClick 按钮的点击事件处理函数,用于在按钮点击时触发通知发布操作。

发布图片类型通知

发布普通文本类型通知,需要设置contentType类型为ContentType.NOTIFICATION_CONTENT_PICTURE

import notification from '@ohos.notificationManager';
import image from '@ohos.multimedia.image';

@Entry
@Component
struct NotificationTest1 {
  async publishPictureNotification() {
    // 将资源图片转化为PixelMap对象
    let resourceManager = getContext(this).resourceManager;
    let imageArray = await resourceManager.getMediaContent($r('app.media.bigPicture').id);
    let imageResource = image.createImageSource(imageArray.buffer);
    let pixelMap = await imageResource.createPixelMap();

    let notificationRequest: notification.NotificationRequest = { // 描述通知的请求
      id: 1,
      content: {
        contentType: notification.ContentType.NOTIFICATION_CONTENT_PICTURE,
        picture: {
          title: '好物热销中', // 通知内容标题
          text: '展开查看详情', // 通知内容
          expandedTitle: '今日热门推荐', // 通知展开时的内容标题
          briefText: '这里一定有您喜欢的', // 通知概要内容,是对通知内容的总结
          picture: pixelMap // 通知的图片内容
        }
      }
    }

    notification.publish(notificationRequest).then(() => { // 发布通知
      console.info('publish success');
    }).catch((err) => {
      console.error(`publish failed, dcode:${err.code}, message:${err.message}`);
    });
  }

  build() {
    Column() {
      Button('发送大图通知')
        .onClick(() => {
          this.publishPictureNotification()
        })
    }
    .width('100%')
  }
}
参数名 作用
notificationRequest 描述通知的请求对象,包含通知的各种信息。
id 通知的唯一标识符,用于区分不同的通知。
content 包含通知内容的对象,指定通知的类型和具体内容。
contentType 指定通知的内容类型,例如图片、普通文本、长文本等。
picture 包含图片类型通知的具体内容信息。
title 图片类型通知的标题。
text 图片类型通知的详细内容。
expandedTitle 图片类型通知展开时的内容标题。
briefText 图片类型通知的概要内容,对通知内容的总结。
picture 图片类型通知的图片内容。
pixelMap 通知的图片内容,通过像素图 (pixelMap) 表示。
publish notification.publish 方法,用于发布通知。
then Promise 的成功回调,用于在通知发布成功后执行的操作。
catch Promise 的失败回调,用于在通知发布失败时处理错误情况。
onClick 按钮的点击事件处理函数,用于在按钮点击时触发通知发布操作。

进度类型通知

进度条通知也是常见的通知类型,主要应用于文件下载事务处理进度显示。目前系统模板仅支持进度条模板。

  • 在发布进度类型通知前需要查询系统是否支持进度条模板

    notification.isSupportTemplate('downloadTemplate').then((data) => {
      console.info(`[ANS] isSupportTemplate success`);
      let isSupportTpl: boolean = data; // isSupportTpl的值为true表示支持支持downloadTemplate模板类通知,false表示不支持
      // ...
    }).catch((err) => {
      console.error(`[ANS] isSupportTemplate failed, error[${err}]`);
    });
    
  • 构造进度条模板,name字段当前需要固定配置为downloadTemplate。

    let template = {
     name: 'downloadTemplate',
     data: {
       progressValue: 60, // 当前进度值
       progressMaxValue: 100 // 最大进度值
      }
    }
    
    let notificationRequest = {
     id: 1,
     content: {
       contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
       normal: {
         title: '文件下载:music.mp4',
         text: 'senTemplate',
         additionalText: '60%'
       }
     },
      template: template  
    }
    // 发布通知
    notification.publish(notificationRequest).then(() => {
     console.info(`publish success`);
    }).catch(error => {
     console.error(`[ANS] publish failed, code is ${error.code}, message is ${error.message}`);
    })
    

更新通知

在发出通知后,使用您之前使用的相同通知ID,再次调用notification.publish来实现通知的更新。如果之前的通知是关闭的,将会创建新通知。

移除通知

// 通过通知ID取消已发布的通知
notification.cancel(notificationId)
// 取消所有已发布的通知
notification.cancelAll()

通知通道

通过通知通道,您可让通知有不同的表现形式,比如社交类型的通知是横幅显示的,并且有提示音,而一般的通知则不会横幅显示,您可以使用slotType来实现。

通知通道类型 显示通知图标 显示横幅 提示音 适用场景
SlotType.SOCIAL_COMMUNICATION 社交应用,如消息、社交媒体等,需要用户及时关注和响应的场景。
SlotType.SERVICE_INFORMATION 服务性应用,如后台服务状态、系统信息等,不需要过于显眼的提示。
SlotType.CONTENT_INFORMATION 内容相关的应用,如新闻、文章更新等,用户更关心通知的内容而非及时响应。
SlotType.OTHER_TYPES 不需要在状态栏中显示图标,通知内容不需要引起用户关注的场景。

后台代理提醒

本节讲述了在HarmonyOS应用中使用后台代理提醒(reminderAgentManager)来添加、发布、删除和修改提醒的基本操作。

后台代理提醒主要有以下几种类型:

  • 倒计时
  • 日历
  • 闹钟

添加使用权限

"module": {
  ...
  "requestPermissions": [
    {
      "name": "ohos.permission.PUBLISH_AGENT_REMINDER"
    }
  ]
}

在应用的 module 配置中添加了后台代理提醒的使用权限。

导入 reminderAgent 模块

import reminderAgent from '@ohos.reminderAgentManager';

通过 @ohos.reminderAgentManager 模块导入后台代理提醒模块,并将其命名为 reminderAgent

新增提醒

export class ReminderService {
  public addReminder(alarmItem: ReminderItem, callback?: (reminderId: number) => void) {
    let reminder = this.initReminder(alarmItem);
    reminderAgent.publishReminder(reminder, (err, reminderId) => {
      if (callback != null) {
        callback(reminderId);
      }
    });
  }
}

使用 reminderAgent.publishReminder 方法发布新的提醒。提醒的具体信息由 ReminderRequestAlarm 类型定义。

删除提醒

export class ReminderService {
  public deleteReminder(reminderId: number) {
    reminderAgent.cancelReminder(reminderId);
  }
}

使用 reminderAgent.cancelReminder 方法删除指定 reminderId 的提醒。

修改提醒

public async setAlarmRemind(alarmItem: AlarmItem) {
  let index = await this.findAlarmWithId(alarmItem.id);
  if (index !== Constants.DEFAULT_NUMBER_NEGATIVE) {
    this.reminderService.deleteReminder(alarmItem.id);
  } else {
    // 处理新增提醒的逻辑
  }

  this.reminderService.addReminder(alarmItem, (newId) => {
    alarmItem.id = newId;
    // 处理新提醒的逻辑
  })
}

在修改提醒时,首先调用 deleteReminder 方法删除旧提醒,然后调用 addReminder 方法添加新提醒。

你可能感兴趣的:(HarmonyOS应用开发,harmonyos)