教程¶
为了掌握基本概念,最好跟随一个分步教程。
在开始之前,请确保您的 widget 树中某处有一个 Column,它将包含我们的教程 widget。
lib/main.dart¶
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [],
)
从 Dart 到 Rust¶
假设要在 Dart 中创建一个新按钮,并通过这个按钮向 Rust 发送一个数字数组和一个字符串。需要有一个信号来通知 Rust 用户事件已发生。
在 hub crate 中编写一个新的信号结构体。请注意,消息上方应标注 DartSignal 属性。
native/hub/src/signals/mod.rs¶
use rinf::DartSignal;
use serde::Deserialize;
#[derive(Deserialize, DartSignal)]
pub struct MyPreciousData {
pub input_numbers: Vec<i32>,
pub input_string: String,
}
接下来,从标注的信号结构体生成 Dart 代码。
CLI¶
rinf gen
在 Dart 中创建一个接受用户输入的按钮 widget。
lib/main.dart¶
import 'package:my_app/src/bindings/bindings.dart';
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
MyPreciousData(
inputNumbers: [3, 4, 5],
inputString: 'Zero-cost abstraction',
).sendSignalToRust(); // GENERATED
},
child: Text('Send a Signal from Dart to Rust'),
),
]
)
让我们在 Rust 中监听此消息。这个简单的函数会将数组中的每个元素加 1,并将字符串中的所有字母大写。
native/hub/src/tutorial_functions.rs¶
use crate::signals::MyPreciousData;
use rinf::{DartSignal, debug_print};
pub async fn calculate_precious_data() {
let receiver = MyPreciousData::get_dart_signal_receiver(); // GENERATED
while let Some(signal_pack) = receiver.recv().await {
let my_precious_data = signal_pack.message;
let new_numbers: Vec<i32> = my_precious_data
.input_numbers
.into_iter()
.map(|x| x + 1)
.collect();
let new_string = my_precious_data.input_string.to_uppercase();
debug_print!("{:?}", new_numbers);
debug_print!("{}", new_string);
}
}
native/hub/src/lib.rs¶
mod tutorial_functions;
use tokio::spawn;
use tutorial_functions::calculate_precious_data;
#[tokio::main]
async fn main() {
spawn(calculate_precious_data());
dart_shutdown().await;
}
现在用 flutter run 运行应用。点击按钮后,我们可以在命令行中看到打印输出!
Output¶
flutter: [4, 5, 6]
flutter: ZERO-COST ABSTRACTION
从 Rust 到 Dart¶
假设您想每秒从 Rust 向 Dart 发送递增的数字。
定义信号结构体。请注意,结构体上方应标注 RustSignal 属性。
native/hub/src/signals/mod.rs¶
use rinf::RustSignal;
use serde::Serialize;
#[derive(Serialize, RustSignal)]
pub struct MyAmazingNumber {
pub current_number: i32,
}
生成 Dart 信号类。
CLI¶
rinf gen
定义一个永远运行的异步 Rust 函数,每秒向 Dart 发送数字。
native/hub/src/tutorial_functions.rs¶
use crate::signals::MyAmazingNumber;
use rinf::RustSignal;
use std::time::Duration;
use tokio::time::interval;
pub async fn stream_amazing_number() {
let mut current_number: i32 = 1;
let mut time_interval = interval(Duration::from_secs(1));
loop {
time_interval.tick().await;
MyAmazingNumber { current_number }.send_signal_to_dart(); // 已生成
current_number += 1;
}
}
native/hub/src/lib.rs¶
mod tutorial_functions;
use tokio::spawn;
use tutorial_functions::stream_amazing_number;
#[tokio::main]
async fn main() {
// ...
tokio::spawn(stream_amazing_number());
dart_shutdown().await;
}
最后,在 Dart 中使用 StreamBuilder 接收信号,并相应地重建 widget。
lib/main.dart¶
import 'package:my_app/src/bindings/bindings.dart';
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// ...
StreamBuilder(
stream: MyAmazingNumber.rustSignalStream, // 已生成
builder: (context, snapshot) {
final signalPack = snapshot.data;
if (signalPack == null) {
return Text('Nothing received yet');
}
final myAmazingNumber = signalPack.message;
final currentNumber = myAmazingNumber.currentNumber;
return Text(currentNumber.toString());
},
),
],
)
双向通信¶
您可以通过结合这两种消息传递方式,轻松地在屏幕上显示更新后的状态。
native/hub/src/signals/mod.rs¶
use rinf::{DartSignal, RustSignal};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, DartSignal)]
pub struct MyTreasureInput {}
#[derive(Serialize, RustSignal)]
pub struct MyTreasureOutput {
pub current_value: i32,
}
CLI¶
rinf gen
lib/main.dart¶
import 'package:my_app/src/bindings/bindings.dart';
children: [
// ...
StreamBuilder(
stream: MyTreasureOutput.rustSignalStream, // 已生成
builder: (context, snapshot) {
final signalPack = snapshot.data;
if (signalPack == null) {
return Text('No value yet');
}
final myTreasureOutput = signalPack.message;
final currentNumber = myTreasureOutput.currentValue;
return Text('Output value is $currentNumber');
},
),
ElevatedButton(
onPressed: () {
MyTreasureInput().sendSignalToRust(); // 已生成
},
child: Text('Send the input'),
),
]
native/hub/src/tutorial_functions.rs¶
use crate::signals::{MyTreasureInput, MyTreasureOutput};
use rinf::{DartSignal, RustSignal};
pub async fn tell_treasure() {
let mut current_value: i32 = 1;
let receiver = MyTreasureInput::get_dart_signal_receiver(); // 已生成
while let Some(_) = receiver.recv().await {
MyTreasureOutput { current_value }.send_signal_to_dart(); // 已生成
current_value += 1;
}
}
native/hub/src/lib.rs¶
mod tutorial_functions;
use tokio::spawn;
use tutorial_functions::tell_treasure;
#[tokio::main]
async fn main() {
// ...
spawn(tell_treasure());
dart_shutdown().await;
}