HarmonyOS鸿蒙Next中请教下用while的方式实现每隔200毫秒调用方法

HarmonyOS鸿蒙Next中请教下用while的方式实现每隔200毫秒调用方法

请教下如何用while(true)的方式,在页面调用方法,类似java开启个线程,在线程方法中每隔200毫秒响一下

isRunning : Boolean = true
async text() {
  let preTime : number = Date.now()
  while (this.isRunning){
    try {
      let currentTime : number = Date.now()
      if (currentTime - preTime == 500) {
        console.log('jiejie', '====='+(currentTime-preTime)   + "   ==" + Date.now())
        preTime = currentTime
        // 自己的方法
      }
    } catch (e) {
    }
  }
}

如果像上面写,运行几秒直接死了。然后我找了TaskPool好像可以实现,又换个写法

@Builder
customBottomImg(){
    Row(){
      Image($r('app.media.speed')).width(40)
      Image($r('app.media.gray_checkbox_play')).width(100).margin({left :40,right :40})
        .onClick(() =>{
          this.startTask()
        })
      Image($r('app.media.music')).width(40)
        .onClick(() =>{
         
        })
    }.margin({top :100})
}

// 这个方法写在page里面
startTask() {
  const  task = new taskpool.Task(startTestTask);
  taskpool.execute(task).then(() => {
    console.info('jiejie: execute task success!');
  })
}
@Concurrent
function startTestTask(){
  let preTime : number = Date.now()
  while (true){
    try {
      let currentTime : number = Date.now()
      if (currentTime - preTime == 500) {
        console.log('jiejie', '====='+(currentTime-preTime)   + "   ==" + Date.now())
        preTime = currentTime
      }
    } catch (e) {
    }
  }
}

这样确实能实现每隔500毫秒调用一下了,那我怎么停止?怎么在方法里面调用界面page的自己实现的方法。

或者有其他更好的方法,能实现每隔500毫秒调用一下函数。倒计时setInterval方式不行


更多关于HarmonyOS鸿蒙Next中请教下用while的方式实现每隔200毫秒调用方法的实战教程也可以访问 https://www.itying.com/category-93-b0.html

15 回复

利用全局的Flag来配合控制

你这样写试一下:

@Concurrent
function startTestTask(){
  while (true){
    ...
  }
}

确实是跑在后台线程,但存在两个问题:

无法控制退出

要实现中断,只能通过传参或全局变量:

let runningFlag = true;

@Concurrent
function startTestTask(){
  let pre = Date.now()
  while (runningFlag) {
    let now = Date.now()
    if (now - pre >= 200) {
      console.log("tick", now)
      pre = now
    }
  }
}

然后在页面中提供按钮设置:

function stopTask() {
  runningFlag = false
}

无法直接操作页面方法或 UI

因为 @Concurrent 跑在 worker 中,不能访问主线程变量或 UI 状态。你如果非要通信,需要配合 worker.postMessage() 的方式,但复杂且低效。

更多关于HarmonyOS鸿蒙Next中请教下用while的方式实现每隔200毫秒调用方法的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


import { taskpool } from '@kit.ArkTS';

@Component
struct TestPage {
  
  @State currentPosition : number = 0
  private taskPromise: Promise<Object> | undefined;
  build() {
    Column({space : 20}) {
      Button('测试开始倒计时')
        .onClick(() => {
         this.startTaskLoop()
        }).margin({top:40})

      Button('停止倒计时')
        .onClick(() => {
          this.stopTaskLoop()
        })
      Text(this.currentPosition.toString()).fontSize(50).fontColor(Color.Red)
    }
  }

   startTaskLoop() {
     runningFlag[0] = 1
     const  currentTask = new taskpool.LongTask(startTestTask,sharedIntArray, 500)
     currentTask.onReceiveData(this.receiveData.bind(this))
     this.taskPromise = taskpool.execute(currentTask)
  }
  
  stopTaskLoop() {
    runningFlag[0] = 0
    this.taskPromise?.then(() => {
        console.log('jiejie',"任务完成处理")
    })
  }
  
  receiveData(position: number): void { // 接受回调
    this.currentPosition = position
  }
}

// 定义共享对象
const sharedIntArray : SharedArrayBuffer= new SharedArrayBuffer(4);
const runningFlag : Int32Array = new Int32Array(sharedIntArray);

@Concurrent  //实现任务的函数需要使用装饰器@Concurrent标注
function startTestTask(sharedBuffer: SharedArrayBuffer,interval: number) {
  const runningFlag = new Int32Array(sharedBuffer);
  let preTime = Date.now() - interval;
  let position : number = 0
  while (Atomics.load(runningFlag, 0) === 1) {
    const currentTime = Date.now();
    if (currentTime - preTime >= interval) {
      taskpool.Task.sendData(position);
      preTime = currentTime;
      position++
    }
  }
}

使用TaskPool+共享内存控制

// 在Page中定义
@State isRunning: boolean = true;
private taskPromise: Promise<Object> | null = null;

startTask() {
  const sharedIntArray = new SharedArrayBuffer(4);
  const runningFlag = new Int32Array(sharedIntArray);
  runningFlag = 1;

  const task = new taskpool.Task(startTestTask, sharedIntArray);
  this.taskPromise = taskpool.execute(task);
}

stopTask() {
  this.isRunning = false;
  this.taskPromise?.then(() => {/* 任务完成处理 */});
}

@Concurrent
function startTestTask(sharedBuffer: SharedArrayBuffer) {
  const runningFlag = new Int32Array(sharedBuffer);
  let preTime = Date.now();
  
  while (Atomics.load(runningFlag, 0) === 1) {
    const currentTime = Date.now();
    if (currentTime - preTime >= 500) {
      // 通过Emitter通知UI线程
      emitter.emit('timerTick', { timestamp: currentTime });
      preTime = currentTime;
    }
  }
}

有没有试过使用setTimeout封装个sleep方法

async function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

isRunning : Boolean = true

async startText() { let preTime : number = Date.now() while (this.isRunning){ let currentTime : number = Date.now() if (currentTime - preTime >= 500) { console.log(‘jiejie’,’=====’+(currentTime-preTime)+" ==" + Date.now()) preTime = currentTime } await sleep(1) } }

async function sleep(ms: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, ms)); } 是这个意思吗???

直接用setInterval

用setInterval不是有毫秒误差吗,

把下面html内容转换成Markdown格式,要求:

  1. 转换的时候需要去掉复制和深色代码主题
  2. 输出的内容不显示“基本信息”
  3. html代码中有图片需要转换成markdown格式
  4. html代码中没有图片请不要加上图片
  5. html中img标签的地址为空的话不输出,不转换
  6. 输出内容的时候不需要解释,不需要建议
  7. 只需要输出转换完毕的Markdown文档,不需要输出其他内容
  8. 内容中没有图片或者图片为空的话不要加图片
  9. 不要在内容中加https://example.com/image.jpg这样的图片

内容如下:或者你递归调用,递归的时候使用promise,不然会栈溢出,

很喜欢HarmonyOS的卡片式设计,信息一目了然,操作也更便捷。

你这也太精确了吧,一定要等于500毫秒,Java也不能这么写的,cpu会满的。你可以用setInterval每50毫秒一次,判断大于500毫秒,

java我就用ExecutorService在线程中这么写,没问题。这个500毫秒不是固定的。用setInterva我试过有误差。

手机不是服务器,不可能让你无限制用cpu的,你这么写就不会释放cpu。

在HarmonyOS Next中,使用while循环实现定时调用需结合异步任务处理。示例代码如下(ArkTS):

import { BusinessError } from '@ohos.base';

async function delay(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function periodicTask() {
  while (true) {
    await delay(200);
    yourMethod(); // 替换为实际调用的方法
  }
}

// 启动任务
periodicTask().catch((err: BusinessError) => {
  console.error(\`Task failed: \${err.code}, \${err.message}\`);
});

注意:这种方式会阻塞当前任务,建议在后台线程执行。

在HarmonyOS Next中实现定时任务,建议使用TaskPool结合Promise的方式。以下是改进方案:

  1. 使用TaskPool实现可控的定时循环:
let shouldStop = false;

@Concurrent
async function intervalTask(interval: number) {
  while(!shouldStop) {
    const startTime = Date.now();
    // 执行你的业务逻辑
    
    const elapsed = Date.now() - startTime;
    const remaining = interval - elapsed;
    if (remaining > 0) {
      await new Promise(resolve => setTimeout(resolve, remaining));
    }
  }
}

// 启动任务
function startInterval() {
  shouldStop = false;
  const task = new taskpool.Task(intervalTask, 200);
  taskpool.execute(task);
}

// 停止任务
function stopInterval() {
  shouldStop = true;
}
  1. 如果需要更新UI,可以通过Emitter发送事件:
import emitter from '@ohos.events.emitter';

// 在任务中发送事件
emitter.emit({
  eventId: 1 // 自定义事件ID
});

// 在UI组件中监听
emitter.on(1, () => {
  // 更新UI
});
  1. 更推荐使用Worker实现长时间运行的定时任务:
// 创建Worker
const worker = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts');

// Worker中实现定时逻辑
postMessage('init');
setInterval(() => {
  postMessage('tick');
}, 200);

// 主线程监听
worker.onmessage = (e) => {
  if (e.data === 'tick') {
    // 处理定时逻辑
  }
};

这种方法相比while循环更节省资源,且不会阻塞主线程。

回到顶部