「鸿蒙 NEXT」基于 taskpool 实现自定义 Timer 工具类

前言

之前在使用原生的 Timer 定时器实现定时任务时,发现当切换页面或应用切换至后台时,Timer 也会被冻结。如何实现可全局调用,支持后台执行的定时任务呢?我想到了使用 taskpool 任务池实现定时任务,在熟练使用 taskpool 实现定时任务后,进一步将其封装为一个自定义 Timer 工具类方便复用。

实现技术

  • 基于 API 12 ,理论上 13 和 14 版本也可以正常使用;
  • taskpool 多线程任务池,原生 Timer 的替代方案,该 API 下有 executeDelayed() 和 executePeriodically() 方法分别可以实现延时任务和周期任务;
  • emitter 事件订阅,类似安卓开发的 eventbus。由于 taskpool 构造时传入的函数,仅允许序列化支持类型作为入参,于是借助 emitter 做一层中转,通知到自定义 Timer 类触发相应的回调。

实现代码

新建文件 FuTimer.ets,所有实现代码写在同一文件下就好。

  1. 设计定时器的回调接口,在接收到 onTask() 回调时,调用需要定时/周期性执行的任务方法:
typescript 复制代码
export interface TimerCallback {
  onStart: () => void;  // 定时器开始
  onCancel: () => void; // 定时器取消
  onTask: () => void;   // 定时任务触发时的回调
}
  1. 自定义工具类 Timer 实现:
kotlin 复制代码
import { taskpool } from "@kit.ArkTS"
import { BusinessError, emitter, systemDateTime } from "@kit.BasicServicesKit";

export class Timer {
  public constructor(callback: TimerCallback) {
    this.timerName =  `futimer_${systemDateTime.getTime()}`;
    this.timerCallback = callback;

    emitter.on(this.timerName, () => {
      if (this.timerCallback) {
        this.timerCallback.onTask();
      }
    });
  }

  private timerName: string;  // 自定义 Timer 唯一名称,与 emitter 订阅事件绑定
  private timerTask: taskpool.Task | undefined;
  private timerCallback: TimerCallback | undefined;

  /*
   * isRepeat: 是否重复执行任务,false 只执行一次, true 会周期性地执行
   * interval:任务执行间隔时间
   */
  public start(isRepeat: boolean, interval: number) {
    // 取消该定时器上一个任务
    if (this.timerTask) {
      this.cancel();
    }
    
    // 开始执行当前任务
    if (this.timerCallback) {
      this.timerCallback.onStart();
    } else {
      return;
    }
    
    // 重置定时任务
    this.timerTask = new taskpool.Task(executeTask, this.timerName);
    if (isRepeat) {
      taskpool.executePeriodically(interval, this.timerTask);
    } else {
      taskpool.executeDelayed(interval, this.timerTask);
    }
  }

  public cancel() {
    try {
      if (this.timerTask) {
        taskpool.cancel(this.timerTask);
      }
    } catch (e) {
      let error = e as BusinessError;
    } finally {
      this.timerTask = undefined;
      if (this.timerCallback) {
        this.timerCallback.onCancel();
      }
    }
  }

  // 销毁定时器,此时再调用 start() 方法无效
  public destroy() {
    this.cancel();
    emitter.off(this.timerName);
    this.timerTask = undefined;
    this.timerCallback = undefined;
  }
}

export interface TimerCallback {
  onStart: () => void;
  onCancel: () => void;
  onTask: () => void;
}

@Concurrent
function executeTask(timerName: string) {
  emitter.emit(timerName);
}

ps:工具类我写在模块下,需要在模块的 Index.ets 中将其 export 出来:

javascript 复制代码
export * as futimer from './src/main/ets/utils/FuTimer'

调用示例

现在使用封装好的定时器工具,实现一个简单的计时功能:

typescript 复制代码
import { futimer } from 'fusdk'; // fusdk 是我定义的本地模块依赖名称,这个不重要了

@Entry
@Component
struct Index {
  @State count: number = 0;

  @State timer: futimer.Timer = new futimer.Timer({
    onStart: () => {
      console.debug('定时器启动');
    },
    onCancel: () => {
      console.debug('定时器取消');
    },
    onTask: () => {
      this.count++;
      console.debug(`第 ${this.count} 次执行任务`);
    }
  });

  build() {
    Column() {
      Text(`现在是第 ${this.count} 秒`)

      Button('开始计时')
        .onClick(() => {
          this.timer.start(true, 1000);
        })

      Button('暂停计时')
        .onClick(() => {
          this.timer.cancel();
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.SpaceEvenly)
  }
}

效果图:

结语

笔者也是正在学习鸿蒙 NEXT 开发的小菜鸟一枚,希望分享的内容能对你有帮助,也欢迎给予建议,今后也会争取在这里分享更多鸿蒙 NEXT 开发相关的内容和经验。

相关推荐
脑极体1 小时前
开源鸿蒙,给机器人带来了什么?
华为·机器人·开源·harmonyos
HarmonyOS_SDK3 小时前
意图框架事件推荐方案,精准匹配用户需求
harmonyos
城中的雾4 小时前
一键多环境构建——用 Hvigor 玩转 HarmonyOS Next
harmonyos
别说我什么都不会4 小时前
【仓颉三方库】分布式——config-client
harmonyos
咸鱼过江4 小时前
openharmony5.0.0中C++公共基础类测试-线程相关(一)
c++·harmonyos
我爱鸿蒙开发5 小时前
🥇聊聊鸿蒙的一端开发,多端部署。
前端·开源·harmonyos
智驾8 小时前
HarmonyOS 是 Android 套壳嘛?
android·harmonyos·替代·套壳
悬空八只脚9 小时前
React-Native开发鸿蒙NEXT-svg绘制睡眠质量图part2
harmonyos
鸿蒙开发工程师—阿辉10 小时前
HarmonyOS Next 编译之如何使用多目标产物不同包名应用
华为·harmonyos