【问题标题】:Flutter UI hangs on async operationFlutter UI 挂在异步操作上
【发布时间】:2019-11-07 13:46:09
【问题描述】:

如何正确构造以下代码?我启动了一个昂贵的异步操作。 “runExpensiveOperation”方法停止旋转的 CircularProgressIndicator,因此它似乎是在主线程上执行的。有没有像原生 iOS 上的“dispatch_async”之类的东西?

class _MyHomePageState extends State<MyHomePage> {

  void _pressed() async {
    print("I am pressed");
    print("I will make a cheap operation now");
    await runExpensiveOperation();
  }

  Future<void> runExpensiveOperation() async  {
    print('starting expensive operation');
    for (var i = 0; i<1000000; i++) {
      List<int> bytes = utf8.encode('somethingtohash');
      String hash = sha256.convert(bytes).toString();
    }
    print('finished expensive operation');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            CircularProgressIndicator(),
            FlatButton(
              child: Text("Press me for tough operation"),
              onPressed: _pressed,
            )
          ],
        ),
      ),
    );
  }
}

【问题讨论】:

  • 你可以在这种情况下使用 Isolates

标签: user-interface asynchronous flutter


【解决方案1】:
class _MyHomePageState extends State<MyHomePage> {

  void _pressed() async {
    print("I am pressed");
    print("I will make a cheap operation now");

    // string returned is "Good Morning"
    String string = await compute(runExpensiveOperation, null); // this is what you need
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            CircularProgressIndicator(),
            FlatButton(
              child: Text("Press me for tough operation"),
              onPressed: _pressed,
            )
          ],
        ),
      ),
    );
  }
}

// make sure this is outside your class definition 
Future<String> runExpensiveOperation(void _) async  {
  print('starting expensive operation');
  for (var i = 0; i<1000000; i++) {
      List<int> bytes = utf8.encode('somethingtohash');
      String hash = sha256.convert(bytes).toString();
  }
  print('finished expensive operation');
  return "Good Morning";
}

【讨论】:

  • 它确实按预期工作。还有一个问题:如何将结果返回给 Widget?假设我想返回一个“完成”的字符串?
  • 首先我确实给出了一个可接受的答案标记,因为它运行良好并且符合我的预期。其次,我真的不明白为什么会这样。 “_pressed”中的“等待”是否让主线程上的事件循环继续操作?为什么主线程在等待时没有被阻塞?
  • 因为这是isolate(独立进程),它有自己的线程和主线程,并且这个线程不共享相同的内存。他们只是来回发送消息,就像我们的隔离将早安消息发送回主线程一样。
  • @CopsOnRoad 如何将参数传递给隔离并执行昂贵的操作?另一个问题是如何收听从隔离发送的消息并在 UI 中显示更新的响应?比如说下载进度
  • @SalarBahador 回答第一个问题,compute 的第二个参数是传递给runExpensiveOperation 的参数。示例代码here
猜你喜欢
  • 2020-10-13
  • 1970-01-01
  • 1970-01-01
  • 2015-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 2018-09-30
相关资源
最近更新 更多