Flutter:多线程Isolate的简单使用

在flutter中如果要使用线程,需要借助Isolate来实现。

简介

在Flutter中,Isolate是一种轻量级的线程解决方案,用于在应用程序中执行并发任务。Isolate可以被认为是独立于主线程的工作单元,它们可以在后台执行任务而不会阻塞应用程序的用户界面。
Isolate提供了多线程编程的能力,允许开发者在应用程序中同时执行多个任务,从而提高应用程序的性能和响应能力。每个Isolate都有自己独立的内存空间和执行环境,它们之间可以通过消息传递进行通信。
在Flutter中,可以使用dart:isolate库来创建和管理Isolate。通过创建一个Isolate对象,可以指定要执行的任务代码。Isolate可以执行耗时的计算、网络请求、文件操作等任务,而不会阻塞应用程序的主线程。
与其他线程解决方案相比,Isolate的一个重要特点是它们之间的内存是隔离的,这意味着每个Isolate都有自己独立的内存空间,它们之间不能直接共享数据。为了在Isolate之间传递数据,可以使用消息传递机制,即将数据打包成消息发送给目标Isolate,并在接收端解包处理。
使用Isolate可以提高应用程序的性能和响应能力,特别是在处理大量计算密集型任务或需要与外部资源进行交互的场景中。然而,需要注意的是,Isolate的创建和销毁都会带来一定的开销,因此在使用Isolate时需要权衡资源消耗和性能提升之间的平衡。
总而言之,Isolate是Flutter中的一种轻量级线程解决方案,用于在应用程序中执行并发任务。它们可以独立于主线程执行任务,并通过消息传递机制进行通信。使用Isolate可以提高应用程序的性能和响应能力,特别是在处理计算密集型任务或需要与外部资源进行交互的场景中。

匿名函数使用

python 复制代码
void _incrementCounter() {
  setState(() {
    _counter++;
  });
  // 匿名线程
  Isolate.spawn((message) {
    print("匿名函数线程:$message");
  }, '哈哈哈');
}

参数会被传递到匿名函数中,并被匿名函数所使用。

普通函数

python 复制代码
 void _incrementCounter() {
   setState(() {
     _counter++;
   });
   // 普通线程
   Isolate.spawn(newThread1, "普通线程");
 }
python 复制代码
// 创建一个额外线程
void newThread1(String message){
  print(message);
}

这个一定要注意,在flutter中使用时newThread1不能写在主进程所在的类里。否则会提示[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Illegal argument in isolate message: object is unsendable - Library:'dart:async' Class: _AsyncCompleter@4048458 (see restrictions listed at SendPort.send() documentation for more information)

子线程向主线程通信

python 复制代码
// 创建一个额外线程
void newThread1(SendPort mainThreadPort) {
  int num = 0;
  Timer.periodic(const Duration(seconds: 1), (timer) {
    // 每隔1秒num加1
    num += 1;
    mainThreadPort.send(num);
    if (num == 10) {
      // 向主进程发消息执行完成
      mainThreadPort.send('stop');
    }
  });
}

class _MyHomePageState extends State<MyHomePage> {
  final receivePort = ReceivePort();

  void _incrementCounter() async {
    // 子线程
    final isolate = await Isolate.spawn(newThread1, receivePort.sendPort);

    // 监听子线程发送的消息
    receivePort.listen((message) {
      print("子线程发送的消息:$message");
      if (message == 'stop') {
        // 执行完成则停止显示
        print("线程执行完成");
        isolate.kill(priority: Isolate.immediate);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: const Center(child: Text("多线程")),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}


主线程向子线程通信

在子线程执行期间,主线程也可以向子线程进行通信。基于上面的代码,进行简单修改

python 复制代码
void newThread1(SendPort mainThreadPort) {
  int num = 0;
  ReceivePort receivePort = ReceivePort();
  Timer.periodic(const Duration(seconds: 1), (timer) {
    // 每隔1秒num加1
    num += 1;
    mainThreadPort.send(num);
    if(num==1){
      // 跟主进程类似,将receivePort.sendPort传递给主进程,主进程才能向子进程通信
      mainThreadPort.send(receivePort.sendPort);
    }
    if (num == 10) {
      // 向主进程发消息执行完成
      mainThreadPort.send('stop');
    }
  });
  // 接收主进程发送的消息
  receivePort.listen((message) {
    print("收到了主进程的消息:$message");
  });
}
python 复制代码
  void _incrementCounter() async {
    // 子线程
    final isolate = await Isolate.spawn(newThread1, receivePort.sendPort);
    late SendPort childSendPort;

    // 监听子线程发送的消息
    receivePort.listen((message) {
      print("子线程发送的消息:$message");
      if (message is SendPort) {
        childSendPort = message;
      }
      if (message == 6) {
        childSendPort.send("加油,马上完成了");
      }
      if (message == 'stop') {
        // 执行完成则停止显示
        print("线程执行完成");
        isolate.kill(priority: Isolate.immediate);
      }
    });
  }

怎么理解呢?

子线程要想向主线程通信,需要获取到主线程的receivePort.sendPort,因此在子线程已创建,就以参数的形式将主线程的receivePort.sendPort传递给子线程。

同理,主线程要想向子线程通信也需要拿到子线程的receivePort.sendPort,因此在子线程一开始执行就将自己的receivePort.sendPort发送给主线程。

只有主线程、子线程都拿到对方的receivePort.sendPort 才可以进行互相通信。

相关推荐
UzumakiHan1 小时前
flutter开发音乐APP(简单的音乐播放demo)
flutter
leluckys5 小时前
flutter 专题 六十四 在原生项目中集成Flutter
flutter
leluckys5 小时前
flutter 专题 一百零四 Flutter环境搭建
flutter
唯鹿5 小时前
AI生成Flutter UI代码实践(一)
人工智能·flutter·ui
仙魁XAN7 小时前
Flutter 学习之旅 之 flutter 有时候部分手机【TextField】无法唤起【输入法软键盘】的一些简单整理
flutter·unity·华为手机·textfield·键盘唤不起
leluckys8 小时前
flutter 专题 五十八 关于Flutter提示Your Xcode project requires migration的错误
flutter
只可远观19 小时前
Flutter Dart中的函数参数 默函数的定义 可选参数 箭头函数 匿名函认参数 命名参类数 闭包等
windows·flutter
JarvanMo1 天前
借助FlutterFire CLI实现Flutter与Firebase的多环境配置
前端·flutter
RichardLai881 天前
[Flutter 基础] - Flutter基础组件 - Icon
android·flutter
汤面不加鱼丸1 天前
flutter实践:比例对比线图实现
前端·flutter