Flutter类型化消息处理插件typed_messages的使用

Flutter类型化消息处理插件typed_messages的使用

消息(Messages)

消息是一段可以在节点之间共享的信息。

让我们定义一个消息:

class ClientInfoMessage extends Message {
  const ClientInfoMessage(this.name, this.avatar, this.clientId)
      : assert(
          name.length <= 20,
          'client info name can not exceed 20 bytes : ${name.length}',
        );

  final int clientId; // 20 bytes Uint
  final String name; // 字符长度在[0, 20]范围内
  final int avatar; // 2 bytes Uint
}

原型(Prototypes)

原型用于在发送前对消息进行编码,并验证和解码传入的消息。

const int kClientInfoMessageId = 0;

// 定义或分配原型到__MessagesPrototypes__单例
IMessagePrototype.definePrototype(const ClientInfoMessagePrototype());

class ClientInfoMessagePrototype implements IMessagePrototype<ClientInfoMessage> {
  const ClientInfoMessagePrototype();

  [@override](/user/override)
  Uint8List encode(ClientInfoMessage message) {
    final writer = BytesWriter(22 + message.name.length);
    writer.writeSingleByte(kClientInfoMessageId); // 写入消息ID
    writer.writeSingleByte(message.name.length); // 写入名称长度
    writer.writeText(message.name); // 写入名称
    writer.writeUint(message.avatar, 2); // 写入头像
    writer.writeUint(message.clientId, 20); // 写入客户端ID
    return writer.toBuffer(); // 返回字节列表
  }

  [@override](/user/override)
  ClientInfoMessage decode(Uint8List bytes) {
    final reader = BytesReader(bytes);
    final int nameLength = reader.readSingleByte(1); // 读取名称长度
    final String name = reader.readText(2, nameLength); // 读取名称
    final int avatar = reader.readUint(2 + nameLength, 2); // 读取头像
    final int id = reader.readUint(4 + nameLength, 20); // 读取客户端ID
    return ClientInfoMessage(name, avatar, id); // 返回解码后的消息
  }

  [@override](/user/override)
  bool validate(Uint8List bytes) {
    final reader = BytesReader(bytes);

    if (reader.length < 22 || reader.length > 42) return false; // 验证字节长度

    final int id = reader.readSingleByte(0); // 读取消息ID
    final int nameLength = reader.readSingleByte(1); // 读取名称长度

    return id == kClientInfoMessageId && nameLength >= 0 && nameLength <= 20; // 验证消息ID和名称长度
  }
}

使用(Usage)

现在我们已经创建了ClientInfoMessage类并定义了其原型ClientInfoMessagePrototype,使用IMessagePrototype.definePrototype方法。

我们有两种方式来编码和解码数据:

方法1:使用Message抽象类
final message = ClientInfoMessage("My Client", 0, 568978596);

final Uint8List bytes = Message.encode(message); // 编码消息

final ClientInfoMessage? decodedMessage = Message.decode(bytes); // 解码消息
方法2:使用MessagesPrototypes单例和原型直接
final instance = MessagesPrototypes.instance;
final message = ClientInfoMessage("My Client", 0, 568978596);

// 编码
final Uint8List? bytes = instance.encodeMessage(message);

// 解码
final ClientInfoMessage? decodedMessage = instance.decodeBytes(bytes!);

// 使用定义的原型
final IMessagePrototype<ClientInfoMessage>? prototype = instance.findPrototypeByMessageType<ClientInfoMessage>();

prototype.encode(message); // 编码消息
prototype.decode(bytes!); // 解码消息
prototype.validate(bytes!); // 验证消息

示例代码

import 'dart:typed_data';

import 'package:typed_messages/typed_messages.dart';

const int kClientInfoMessageId = 0;

class ClientInfoMessage extends Message {
  const ClientInfoMessage(this.name, this.avatar, this.clientId)
      : assert(
          name.length >= 0 && name.length <= 20,
          'name length must be in range [0, 20] characters',
        );

  final String name;
  final int avatar;
  final int clientId;
}

class ClientInfoMessagePrototype
    implements IMessagePrototype<ClientInfoMessage> {
  const ClientInfoMessagePrototype();

  [@override](/user/override)
  Uint8List encode(ClientInfoMessage message) {
    final writer = BytesWriter(22 + message.name.length);
    writer.writeSingleByte(kClientInfoMessageId);
    writer.writeSingleByte(message.name.length);
    writer.writeText(message.name);
    writer.writeUint(message.avatar, 2);
    writer.writeUint(message.clientId, 20);
    return writer.toBuffer();
  }

  [@override](/user/override)
  ClientInfoMessage decode(Uint8List bytes) {
    final reader = BytesReader(bytes);
    final int nameLength = reader.readSingleByte(1);
    final String name = reader.readText(2, nameLength);
    final int avatar = reader.readUint(2 + nameLength, 2);
    final int clientId = reader.readUint(4 + nameLength, 20);
    return ClientInfoMessage(name, avatar, clientId);
  }

  [@override](/user/override)
  bool validate(Uint8List bytes) {
    final reader = BytesReader(bytes);
    if (reader.length < 22 || reader.length > 42) return false;
    final int id = reader.readSingleByte(0);
    final int nameLength = reader.readSingleByte(1);
    return id == kClientInfoMessageId && nameLength >= 0 && nameLength <= 20;
  }
}

void main() {
  IMessagePrototype.definePrototype(const ClientInfoMessagePrototype());

  final message = ClientInfoMessage("My Client", 0, 568978596);
  Uint8List bytes;
  ClientInfoMessage? decodedMessage;

  // 编码
  bytes = Message.encode(message);

  // 解码
  decodedMessage = Message.decode<ClientInfoMessage>(bytes);

  // 使用MessagesPrototypes实例
  final instance = MessagesPrototypes.instance;
  final IMessagePrototype<ClientInfoMessage>? prototype =
      instance.findPrototypeByMessageType<ClientInfoMessage>();

  bytes = prototype!.encode(message);
  final bool isValidBytes = prototype.validate(bytes);
  decodedMessage = prototype.decode(bytes);
}

更多关于Flutter类型化消息处理插件typed_messages的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter类型化消息处理插件typed_messages的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


typed_messages 是一个用于 Flutter 的类型化消息处理插件,它允许你在 Flutter 应用中发送和接收类型化的消息。这个插件特别适用于需要在不同组件或模块之间进行通信的场景。通过使用 typed_messages,你可以确保消息的类型安全,并减少运行时错误。

安装

首先,你需要在 pubspec.yaml 文件中添加 typed_messages 依赖:

dependencies:
  flutter:
    sdk: flutter
  typed_messages: ^0.1.0  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

基本用法

1. 定义消息类型

首先,你需要定义消息的类型。你可以通过继承 TypedMessage 来创建自定义的消息类型。

import 'package:typed_messages/typed_messages.dart';

class MyMessage extends TypedMessage {
  final String content;

  MyMessage(this.content);
}

2. 创建消息处理器

接下来,你需要创建一个消息处理器来处理特定类型的消息。你可以通过继承 TypedMessageHandler 来实现。

class MyMessageHandler extends TypedMessageHandler<MyMessage> {
  @override
  void handle(MyMessage message) {
    print('Received message: ${message.content}');
  }
}

3. 注册消息处理器

然后,你需要将消息处理器注册到 TypedMessageDispatcher 中。

void main() {
  final dispatcher = TypedMessageDispatcher();
  dispatcher.registerHandler(MyMessageHandler());
}

4. 发送消息

最后,你可以通过 TypedMessageDispatcher 发送消息。

void main() {
  final dispatcher = TypedMessageDispatcher();
  dispatcher.registerHandler(MyMessageHandler());

  // 发送消息
  dispatcher.dispatch(MyMessage('Hello, World!'));
}

高级用法

处理多个消息类型

你可以注册多个消息处理器来处理不同类型的消息。

class AnotherMessage extends TypedMessage {
  final int number;

  AnotherMessage(this.number);
}

class AnotherMessageHandler extends TypedMessageHandler<AnotherMessage> {
  @override
  void handle(AnotherMessage message) {
    print('Received number: ${message.number}');
  }
}

void main() {
  final dispatcher = TypedMessageDispatcher();
  dispatcher.registerHandler(MyMessageHandler());
  dispatcher.registerHandler(AnotherMessageHandler());

  // 发送不同类型的消息
  dispatcher.dispatch(MyMessage('Hello, World!'));
  dispatcher.dispatch(AnotherMessage(42));
}

异步消息处理

如果你的消息处理逻辑是异步的,你可以在 handle 方法中使用 asyncawait

class AsyncMessageHandler extends TypedMessageHandler<MyMessage> {
  @override
  Future<void> handle(MyMessage message) async {
    await Future.delayed(Duration(seconds: 1));
    print('Async message received: ${message.content}');
  }
}

取消注册处理器

如果你不再需要某个消息处理器,可以将其取消注册。

void main() {
  final dispatcher = TypedMessageDispatcher();
  final handler = MyMessageHandler();
  dispatcher.registerHandler(handler);

  // 取消注册处理器
  dispatcher.unregisterHandler(handler);
}
回到顶部