Flutter应用程序冻结,无法正常运行

时间:2018-09-26 13:58:52

标签: dart flutter

我有一个Flutter应用程序,有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)),          
          ]
        ),
      ),
    );
  }
}

4 个答案:

答案 0 :(得分:3)

那是因为您处于无限循环中,所以更好的方法是使用计时器:

  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)),
              ]),
        ),
      );
    }
  }

答案 1 :(得分:0)

来自睡眠文档

  

请谨慎使用此选项,因为在睡眠调用中被阻塞时,无法单独处理任何异步操作。

setState内部不应包含逻辑,而应仅用于更改值。

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

我会那样做

Timer _timer;

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

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

答案 2 :(得分:0)

使用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);
    }
  }
}

答案 3 :(得分:0)

这是秒表的示例代码。

enter image description here

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"),
            ),
          ],
        ),
      ),
    );
  }
}