鸿蒙中 TaskPool与宿主线程通信解析

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、TaskPool 线程通信

1. 场景

  • 实时状态通知:任务执行过程中需要定时向宿主线程报告进度

  • 分段数据返回:处理大量数据时分段返回,避免长时间等待

  • 中间结果获取:在任务完成前获取部分计算结果

2. 与传统方式的区别

通信方式返回时机数据形式适用场景
传统execute()任务完成后一次性返回最终结果简单任务
sendData()通信任务执行过程中多次返回进度、分段数据复杂长任务

二、线程通信的实现机制

1. 核心通信接口

  • 发送端taskpool.Task.sendData() - 在任务线程中发送数据

  • 接收端task.onReceiveData() - 在宿主线程中接收数据

  • 回调函数:用户定义的消息处理函数

三、实现步骤

步骤1:定义数据模型

// ImageDataModel.ets
export class ImageItem {
  imageUrl: string | Resource = '';
  title: string | Resource = '';
  
  constructor(imageUrl: string | Resource = '', title: string | Resource = '') {
    this.imageUrl = imageUrl;
    this.title = title;
  }
}

步骤2:创建消息接收处理函数

// TaskCommunication.ets
export function handleProgressUpdate(progressData: number): void {
  // 处理从任务线程接收到的进度数据
  console.info("后台任务执行进度: ", progressData);
  
  // 可以在这里更新UI进度条、显示提示信息等
 
}

步骤3:实现支持通信的任务函数

// TaskCommunication.ets
import { taskpool } from '@kit.ArkTS';
import { ImageItem } from './ImageDataModel';

@Concurrent
export function processImagesWithProgress(imageCount: number): ImageItem[] {
  let processedImages: ImageItem[] = [];
  
  // 模拟处理多个图片
  for (let i = 0; i < imageCount; i++) {
    const batchStart = i * 3;
    
    // 添加图片数据到结果列表
    processedImages.push(new ImageItem('$media:homeIcon', `图片${batchStart + 1}`));
    processedImages.push(new ImageItem('$media:galleryIcon', `图片${batchStart + 2}`));
    processedImages.push(new ImageItem('$media:documentIcon', `图片${batchStart + 3}`));
    
    // 关键:发送进度更新到宿主线程
    const currentProgress = processedImages.length;
    taskpool.Task.sendData(currentProgress);
    
    // 模拟耗时操作
    if (i % 4 === 0) {
      console.info(`已处理 ${currentProgress} 张图片`);
    }
  }
  
  return processedImages;
}

步骤4:在宿主线程中配置和使用

// MainPage.ets
import { taskpool } from '@kit.ArkTS';
import { ImageItem } from './ImageDataModel';
import { processImagesWithProgress, handleProgressUpdate } from './TaskCommunication';

@Entry
@Component
struct MainPage {
  @State pageTitle: string = '图片处理进度演示';
  @State progressInfo: string = '准备开始';
  @State finalResult: ImageItem[] = [];
  @State currentProgress: number = 0;
  @State totalItems: number = 0;

  build() {
    Column() {
      Text(this.pageTitle)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 10 })
      
      Text(this.progressInfo)
        .fontSize(16)
        .fontColor(Color.Blue)
        .margin({ bottom: 20 })
      
      Text(`处理进度: ${this.currentProgress} 项`)
        .fontSize(14)
        .margin({ bottom: 10 })
      
      Button('开始处理图片')
        .fontSize(18)
        .padding(10)
        .backgroundColor(Color.Green)
        .onClick(() => {
          this.startImageProcessing();
        })
        .margin({ bottom: 20 })
      
      if (this.finalResult.length > 0) {
        Text(`处理完成,共 ${this.finalResult.length} 张图片`)
          .fontSize(16)
          .fontColor(Color.Green)
      }
    }
    .padding(20)
    .width('100%')
  }

  private async startImageProcessing(): Promise<void> {
    try {
      // 重置状态
      this.progressInfo = '开始处理图片...';
      this.currentProgress = 0;
      this.finalResult = [];
      
      // 创建任务实例
      const imageProcessingTask: taskpool.Task = new taskpool.Task(processImagesWithProgress, 25);
      
      // 关键:设置数据接收回调函数
      imageProcessingTask.onReceiveData(this.handleTaskData.bind(this));
      
      // 执行任务
      this.finalResult = await taskpool.execute(imageProcessingTask) as ImageItem[];
      
      // 任务完成后的处理
      this.progressInfo = `图片处理完成!总共 ${this.finalResult.length} 张`;
      this.totalItems = this.finalResult.length;
      
      console.info(`最终结果: 共处理 ${this.finalResult.length} 张图片`);
      
    } catch (error) {
      console.error(`图片处理失败: ${error}`);
      this.progressInfo = '处理失败,请重试';
    }
  }

  private handleTaskData(progressData: number): void {
    // 更新进度状态
    this.currentProgress = progressData;
    this.progressInfo = `正在处理... 已完成 ${progressData} 项`;
    
    // 可以在这里添加更多的进度处理逻辑
    if (progressData % 20 === 0) {
      console.info(`进度更新: 已完成 ${progressData} 项操作`);
    }
  }
}

四、技术细节

1. sendData() 方法特性

// 在 @Concurrent 函数中使用
@Concurrent
function exampleTask(param: number): ResultType {
  // 处理逻辑...
  
  // 发送进度数据(支持基本数据类型)
  taskpool.Task.sendData(progressValue);
  
  // 继续处理...
  return finalResult;
}

支持的数据类型

  • number、string、boolean 等基本类型

  • 支持序列化的对象

  • 注意:数据量应符合序列化限制(16MB)

2. onReceiveData() 回调配置

// 回调函数签名要求
type DataCallback = (data: any) => void;

// 配置回调的时机
const task = new taskpool.Task(taskFunction, ...args);

// 必须在 execute() 之前设置回调
task.onReceiveData((progress) => {
  // 处理接收到的数据
  updateProgressBar(progress);
});

// 然后执行任务
await taskpool.execute(task);

五、通信机制

1. 数据流方向

任务线程 (TaskPool Worker)
    ↓ 通过 taskpool.Task.sendData()
消息队列
    ↓ 通过 task.onReceiveData() 
宿主线程 (UI Thread)
    ↓ 调用回调函数
用户界面更新

2. 线程安全保证

  • 消息传递是线程安全的

  • 数据会自动序列化和反序列化

  • 回调函数在宿主线程中执行,可以安全更新UI

六、总结

  • 使用 taskpool.Task.sendData() 在任务线程中发送数据

  • 使用 task.onReceiveData() 在宿主线程中接收数据

  • 确保在调用 execute() 之前设置好回调函数

  • 合理控制消息发送频率,平衡实时性和性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值