Flutter隔离执行插件use_isolate的使用

Flutter隔离执行插件use_isolate的使用

integral_isolates 的强大功能被巧妙地封装在了一个 flutter_hooks 的钩子中。

使用方法

使用隔离(isolate)在钩子中从未如此简单。通过使用 useIsolate(),你可以获得一个类似于 compute 的计算函数,但它的生命周期更长。你无需关心生命周期管理,因为钩子会为你处理。

示例代码:

class TestingIsolateHook extends HookWidget {
  const TestingIsolateHook({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    final isolate = useIsolate(); // 获取一个隔离实例
    final number = useState(1); // 定义一个状态变量

    return TextButton(
      onPressed: () async {
        final isPrime = await isolate.compute(_isPrime, number.value); // 在隔离中执行计算
        print('${number.value} 是素数吗? ${isPrime}');
        number.value += 1; // 更新状态变量
      },
      child: Text(
        '检查 ${number.value} 是否为素数',
      ),
    );
  }

  static bool _isPrime(int value) {
    if (value == 1) {
      return false;
    }
    for (int i = 2; i < value; ++i) {
      if (value % i == 0) {
        return false;
      }
    }
    return true;
  }
}

说明:

  • useIsolate() 返回一个隔离实例。
  • useState() 定义一个可变的状态变量。
  • isolate.compute() 在隔离中执行计算。
  • number.value += 1 更新状态变量。

回压策略

该钩子支持回压策略(backpressure strategies)。只需将策略作为参数传递即可:

final isolate = useIsolate(backpressureStrategy: DiscardNewBackPressureStrategy());

尾调隔离(Tailored Stateful Isolate)

你可能知道,你可以用 integral_isolates 创建尾调隔离。现在,使用 use_isolate 也可以实现这一点。

创建一个接收 double 类型输入并返回 int 类型结果的尾调隔离,可以这样使用:

final isolate = useTailoredIsolate<double, int>();

突破性变更

  • use_isolate v0.3.0:现在返回整个隔离实例,需要显式调用 isolate.compute(...) 而不是 isolate(...). 这是为了支持 isolate.computeStream(...)

额外信息

虽然这个 API 大部分是稳定的,但底层包(integral_isolates)的实现尚未完全定型,未来会有更多特性加入,直到两个包都稳定下来。


完整示例Demo

import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:use_isolate/use_isolate.dart';

void main() {
  runApp(const MaterialApp(home: OuterWidget()));
}

class OuterWidget extends HookWidget {
  const OuterWidget({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    final isTesting = useState<bool>(false);

    return Scaffold(
      appBar: AppBar(
        title: InkWell(
          child: const Text('插件示例应用'),
          onTap: () {
            isTesting.value = !isTesting.value;
          },
        ),
      ),
      body: isTesting.value
          ? const IsolateTestingWidget()
          : const Center(child: Text("当前未测试")),
    );
  }
}

class IsolateTestingWidget extends HookWidget {
  const IsolateTestingWidget({super.key});

  static String _hello(_MethodInput input) {
    sleep(input.delay);
    return input.text;
  }

  static String _error(_MethodInput input) {
    sleep(input.delay);
    throw Exception('错误');
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    final isolate = useIsolate();
    final tailoredIsolate = useTailoredIsolate<_MethodInput, String>(
      backpressureStrategy: CombineBackPressureStrategy(
        (oldData, newData) {
          return _MethodInput(oldData.text + newData.text);
        },
      ),
    );

    Future<String?> safeHello(_MethodInput input) async {
      try {
        return await tailoredIsolate.compute(_hello, input);
      } catch (e) {
        return null;
      }
    }

    return ListView(
      children: [
        TextButton(
          onPressed: () async {
            final hi = await compute(_hello, _MethodInput("hi"));
            print(hi);
          },
          child: const Text('运行 compute'),
        ),
        TextButton(
          onPressed: () async {
            final hi =
                _hello(_MethodInput("hi", delay: const Duration(seconds: 2)));
            print(hi);
          },
          child: const Text('阻塞'),
        ),
        TextButton(
          onPressed: () async {
            final hi = await isolate.compute(
                _hello, _MethodInput("hi", delay: const Duration(seconds: 2)));
            print(hi);
          },
          child: const Text('运行一次'),
        ),
        TextButton(
          onPressed: () async {
            final yo = await isolate.compute(_hello, _MethodInput("yo"));
            print(yo);
          },
          child: const Text('运行其他'),
        ),
        TextButton(
          onPressed: () async {
            final hi = await isolate.compute(_hello, _MethodInput("hi"));
            print(hi);
            final yo = await isolate.compute(_hello, _MethodInput("yo"));
            print(yo);
          },
          child: const Text('队列中运行两个'),
        ),
        TextButton(
          onPressed: () async {
            isolate.compute(_hello, _MethodInput("hi")).then(print);
            isolate
                .compute(
                  _hello,
                  _MethodInput(
                    "yo",
                    delay: const Duration(milliseconds: 500),
                  ),
                )
                .then(print);
          },
          child: const Text('并行运行两个,监听值'),
        ),
        TextButton(
          onPressed: () async {
            final responses = await Future.wait(
              [
                isolate.compute(_hello, _MethodInput("hi")),
                isolate.compute(
                  _hello,
                  _MethodInput("ho", delay: const Duration(milliseconds: 500)),
                ),
              ],
            );
            print(responses);
          },
          child: const Text('使用 Future.wait 并行运行两个'),
        ),
        TextButton(
          onPressed: () async {
            final responses = await Future.wait(
              [
                safeHello(_MethodInput("hi")),
                safeHello(
                  _MethodInput("ho", delay: const Duration(milliseconds: 500)),
                ),
                safeHello(_MethodInput("hi")),
                safeHello(_MethodInput("hi")),
              ],
            );
            print(responses);
          },
          child: const Text('使用尾调隔离'),
        ),
        TextButton(
          onPressed: () async {
            final hi = await isolate.compute(_error, _MethodInput("hi"));
            print(hi);
          },
          child: const Text('错误'),
        ),
        const Center(child: CircularProgressIndicator()),
      ],
    );
  }
}

class _MethodInput {
  final String text;
  final Duration delay;

  _MethodInput(
    this.text, {
    this.delay = const Duration(seconds: 1),
  });
}

更多关于Flutter隔离执行插件use_isolate的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter隔离执行插件use_isolate的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用use_isolate插件来隔离执行代码的示例。use_isolate插件允许你在Flutter应用中隔离执行耗时的操作,从而避免阻塞UI线程。

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

dependencies:
  flutter:
    sdk: flutter
  use_isolate: ^x.y.z  # 请替换为最新的版本号

然后运行flutter pub get来获取依赖。

接下来,我们来看一个具体的代码示例,演示如何使用use_isolate来隔离执行一个耗时的计算任务。

import 'package:flutter/material.dart';
import 'package:use_isolate/use_isolate.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('use_isolate Example'),
        ),
        body: Center(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String result = 'Calculating...';

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text(
          result,
          style: TextStyle(fontSize: 24),
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: () async {
            setState(() {
              result = 'Calculating...';
            });

            final computeResult = await computeIsolate(() {
              // 模拟一个耗时的计算任务
              return intensiveComputation();
            });

            setState(() {
              result = 'Result: $computeResult';
            });
          },
          child: Text('Start Computation'),
        ),
      ],
    );
  }

  // 定义一个耗时的计算函数
  int intensiveComputation() {
    int sum = 0;
    for (int i = 0; i < 100000000; i++) {
      sum += i;
    }
    return sum;
  }
}

// 使用use_isolate的computeIsolate函数替代dart:isolate的compute函数
Future<T> computeIsolate<T>(FutureOr<T> Function() fn) async {
  final isolateResult = await compute(fn, null, debugLabel: 'Isolate #1');
  return isolateResult as T;
}

注意:上面的代码示例中,computeIsolate函数实际上并没有直接使用use_isolate插件的特定功能,因为use_isolate主要是为了解决在Flutter Web等不支持dart:isolate的环境中运行隔离代码的问题。在支持dart:isolate的环境中(如Flutter Mobile),你可以直接使用dart:isolate库的compute函数。

但是,如果你需要在Flutter Web上使用隔离执行,use_isolate插件提供了一种替代方案。这里为了保持示例的通用性,我们仍然使用compute函数。如果你需要在Web上运行,你应该查看use_isolate的文档,了解如何正确配置和使用它。

对于Flutter Web,你可能需要像这样配置use_isolate

import 'package:use_isolate/use_isolate.dart';

void main() async {
  // 配置use_isolate以支持Flutter Web
  await configureIsolateBinaries();

  runApp(MyApp());
}

确保在调用任何隔离执行代码之前配置好use_isolate

请根据你的具体需求调整上述代码,并查阅use_isolate的官方文档以获取更多详细信息和高级用法。

回到顶部