Flutter应用冻结并且无法按预期工作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)),          
          ]
        ),
      ),
    );
  }
}
答案

那是因为你处于无限循环中,更好的方法是使用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)),
              ]),
        ),
      );
    }
  }
另一答案

来自睡眠文档

请谨慎使用,因为隔离区在睡眠调用中被阻止时,不能处理异步操作。

你不应该在setState中有逻辑,它应该只用于改变值。

据我所知,你想要启动一个计时器,每隔几秒就更新一次。

我会这样做的

Timer _timer;

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

...
dispose() {
  super.dispose();
  _timer?.cancel();
}
另一答案

使用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);
    }
  }
}
另一答案

这是秒表的示例代码。

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

以上是关于Flutter应用冻结并且无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 嵌套小部件 setState 无法按预期工作

Flutter - 使用提供程序时 whenComplete() 无法按预期工作

whenComplete() 方法没有按预期工作 - Flutter Async

Flutter 本地通知在 IOS 上未按预期工作

C# 信号量没有按预期工作,无法弄清楚原因

MPMoviePlayerController:搜索按钮点击冻结视频 - 黑屏