【问题标题】:Flutter app freezes and doesn't work as expectedFlutter 应用程序冻结并且无法按预期工作
【发布时间】:2018-09-26 13:58:52
【问题描述】:

我有一个颤振应用,有 2 个页面。第一个页面是一个简单的 InkWell,它将用户发送到第 2 页。当点击第 2 页时,计时器应该每秒递减一次。它不会开始增量,而是冻结。

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


int _time = 60;
bool _restart = false;

class MainPage extends StatefulWidget {
  @override
  MainPageState createState() => new MainPageState();
}

class MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
      return new Material(
      color: Colors.greenAccent,
      child: new InkWell(
        onTap: () {
          setState((){
            while ( true ) {
              sleep(const Duration(seconds:1));
              _time = _time - 1;
            }
          });
        },
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(_time.toString(), style: new TextStyle(color:             
Colors.white, fontSize: 60.0, fontWeight: FontWeight.bold)),          
          ]
        ),
      ),
    );
  }
}

【问题讨论】:

  • 我认为是因为你调用了 setState 并且它里面是无限循环。您可以尝试类似 onTap: () { while ( true ) { setState((){ sleep(const Duration(seconds:1)); _time = _time - 1; }); } }

标签: dart flutter


【解决方案1】:

那是因为你处于无限循环中,更好的方法是使用 Timer:

  class TimerSample extends StatefulWidget {
    @override
    _TimerSampleState createState() => _TimerSampleState();
  }

  class _TimerSampleState extends State<TimerSample> {
    int _time = 60;
    bool _restart = false;
    Timer timer;

    _onTap() {
      if (timer == null) {
        timer = Timer.periodic(Duration(seconds: 1), (Timer t) {
          _time = _time - 1;

          //your conditions here
          //call setState if you want to refresh the content
        });
      }
    }

    @override
    void dispose() {
      if (timer != null) {
        timer.cancel();
      }
      super.dispose();
    }

    @override
    Widget build(BuildContext context) {
      return new Material(
        color: Colors.greenAccent,
        child: new InkWell(
          onTap: _onTap,
          child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Text(_time.toString(),
                    style: new TextStyle(
                        color: Colors.white,
                        fontSize: 60.0,
                        fontWeight: FontWeight.bold)),
              ]),
        ),
      );
    }
  }

【讨论】:

  • 谢谢!另外,你是怎么得到语法高亮的?
  • 哪个突出显示?我看到你的代码也突出显示
  • 奇怪,我自己的看不到?
  • 这很奇怪,我用的是 chrome 而你呢?
  • 对不起,我忘记了周期性工厂构造函数,再次检查代码
【解决方案2】:

来自睡眠文档

谨慎使用它,因为当它在睡眠调用中被阻塞时,不能在隔离中处理任何异步操作。

你不应该在 setState 里面有逻辑,它应该只用来改变值。

据我了解,您想启动一个计时器,每秒钟更新一次您的用户界面。

我会那样做的

Timer _timer;

...
_timer ??= new Timer.periodic(const Duration(seconds:1), () {
    setState(() {
      _time = _time - 1;
    });
 })

...
dispose() {
  super.dispose();
  _timer?.cancel();
}

【讨论】:

    【解决方案3】:

    使用AnimatedBuilder 可以避免调用setState 来更新计数器文本。否则,您最终可能会为了更新动画而不必要地重新构建小部件。

    class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
      int _startTime = 10;
      Duration _totalTime;
      AnimationController _controller;
    
      @override
      void initState() {
        _totalTime = Duration(seconds: _startTime);
        _controller = AnimationController(
          vsync: this,
          duration: _totalTime,
        );
        super.initState();
      }
    
      @override
      void dispose() {
        super.dispose();
        _controller.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Material(
          color: Colors.greenAccent,
          child: InkWell(
            onTap: () {
              if (_timeLeft().inMicroseconds == 0) {
                _controller.reset();
              } else {
                if (!_controller.isAnimating) {
                  _controller.forward();
                } else {
                  _controller.stop(canceled: false);
                }
              }
            },
            child: AnimatedBuilder(
              animation: _controller,
              builder: (BuildContext context, Widget child) {
                return Center(
                    child: Text(
                  '${_timeLeft().inSeconds}',
                  style: TextStyle(
                    fontSize: 60.0,
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                  ),
                ));
              },
            ),
          ),
        );
      }
    
      Duration _timeLeft() {
        final timeLeft = _totalTime - (_totalTime * _controller.value);
        if (timeLeft.inMicroseconds == 0 || timeLeft == _totalTime) {
          return timeLeft;
        } else {
          return timeLeft + const Duration(seconds: 1);
        }
      }
    }
    

    【讨论】:

      【解决方案4】:

      这是一个秒表的示例代码。

      void main() => runApp(MyApp());
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            home: HomePage(),
          );
        }
      }
      
      class HomePage extends StatefulWidget {
        @override
        _HomePageState createState() => _HomePageState();
      }
      
      class _HomePageState extends State<HomePage> {
        int _count = 0;
        bool _flag1 = false;
        bool _flag2 = false;
      
        void _startCounter() {
          _flag1 = true;
          if (!_flag2) {
            _flag2 = true;
            Timer.periodic(Duration(milliseconds: 1000), (Timer timer) {
              setState(() {
                if (_flag1) _count++;
              });
            });
          }
        }
      
        void _stopCounter() {
          _flag1 = false;
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text("Stopwatch"),
            ),
            body: Center(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  RaisedButton(
                    onPressed: _startCounter,
                    child: Text("Start"),
                  ),
                  Text(_count.toString()),
                  RaisedButton(
                    onPressed: _stopCounter,
                    child: Text("Stop"),
                  ),
                ],
              ),
            ),
          );
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多