Flutter timer的使用

作者: 木子雨廷t | 来源:发表于2022-11-02 14:04 被阅读0次
    timer在实际的项目开发中用的不是很多,但是对于一些订单的页面还是会用的到,网上关于timer的资料不是很多,对于一些复杂的使用场景没有提到.此文根据在实际项目中的使用整理了一个demo.再此开源,纯属技术交流,欢迎评论交流.
    先展示一下最终的实现效果
    最终实现效果

    实现思路:
    实现思路就是界面里面使用一个定时器,然后在倒计时里对数据源里面的时间字段就行减一操作,再刷新界面就可以了,思路很简单.但是定时器废了劲了.

    遇到问题:

    下拉刷新定时器加速问题

    问题代码:

    class TimerPage extends StatefulWidget {
      const TimerPage({Key? key}) : super(key: key);
    
      @override
      State<TimerPage> createState() => _TimerPageState();
    }
    
    class _TimerPageState extends State<TimerPage> {
      late Timer _timer;
      List dataList = [
        500,
        620,
        700,
        820,
        960,
        180,
        200,
        220,
      ];
      late EasyRefreshController _controller;
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        _controller = EasyRefreshController(
        );
        creatData();
      }
    
      void creatData() {
        var date = DateTime.parse("2022-11-10 21:20:41");
        var today = DateTime.now();
        var difference = date.difference(today);
        int timeCount = difference.inSeconds;
        dataList.insert(0, timeCount);
        startTimer();
      }
    
      void startTimer() {
        // _timer.cancel();
        // _timer = null;
        List list = dataList;
        _timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
          for (int i = 0; i < list.length; i++) {
            var tempTime = list[i];
            if (tempTime == 0) {
            } else {
              tempTime -= 1;
            }
            list[i] = tempTime;
          }
          print('哈哈哈哈哈哈哈');
          setState(() {
            dataList = list;
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        /// 写一个下拉刷新的列表 定时器加速问题
        return Scaffold(
          appBar: AppBar(
            title: const Text('定时器使用'),
          ),
          body: EasyRefresh(
            controller: _controller,
            firstRefresh: false,
            header: ClassicalHeader(),
            footer: ClassicalFooter(),
            onRefresh: () async {
              await Future.delayed(const Duration(seconds: 1));
              creatData();
              _controller.resetLoadState();
            },
            child: ListView.builder(
                shrinkWrap: true,
                physics: const AlwaysScrollableScrollPhysics(),
                itemCount: dataList.length,
                itemBuilder: (BuildContext context, int index) {
                  return Container(
                    height: 50,
                    alignment: Alignment.center,
                    margin: const EdgeInsets.only(left: 15, right: 15, top: 15),
                    decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(6),
                        boxShadow: const [
                          BoxShadow(
                              color: Colors.black12,
                              offset: Offset(0.0, 0.0), //阴影xy轴偏移量
                              blurRadius: 2.0, //阴影模糊程度
                              spreadRadius: 2.0 //阴影扩散程度
                          )
                        ]),
                    child: Text(
                      FormatUtils.constructTime(dataList[index]),
                      style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
                    ),
                  );
                }),
          )
        );
      }
    
      @override
      void dispose() {
        // TODO: implement dispose
        super.dispose();
        _timer.cancel();
        // _timer = null;
        _controller.dispose();
      }
    }
    
    

    late关键字显式声明一个非空的变量,但不初始化。
    如果不加late关键字,类实例化时此值是不确定的,无法通过静态检查,加上late关键字可以通过静态检查,但由此会带来运行时风险。但是我在下拉刷新的时候timer又重新创建了一个,所以就出现了定时器的加速的问题.我在定时器里面打印了内容,发现下拉刷新一次之后,打印的内容是两个两个打印的,在退出当前页面以后还有一个定时器在打印.所以,一开始我就在startTimer方法里添加了_timer.cancel()这行代码,发现timer停止了,一个都不走了.我当时思考给timer加一个final,修改代码如下'_timer@484517720' has already been initialized.就可以解决这个问题,结果下拉刷新时报错了_timer@484517720' has already been initialized.提示timer对象已经存在了,不能重复创建.是因为final 表示单分配,最终变量或字段必须具有初始化程序。一旦分配了值最终变量的值就无法更改。
    最后又经过了一番尝试,终于解决了这个问题,先上代码.

    class TimerPage extends StatefulWidget {
      const TimerPage({Key? key}) : super(key: key);
    
      @override
      State<TimerPage> createState() => _TimerPageState();
    }
    
    class _TimerPageState extends State<TimerPage> {
      Timer? _timer;
      List dataList = [
        500,
        620,
        700,
        820,
        960,
        180,
        200,
        220,
      ];
      late EasyRefreshController _controller;
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        _controller = EasyRefreshController(
        );
      }
    
      void creatData() {
        var date = DateTime.parse("2022-11-10 21:20:41");
        var today = DateTime.now();
        var difference = date.difference(today);
        int timeCount = difference.inSeconds;
        dataList.insert(0, timeCount);
        startTimer();
      }
    
      void startTimer() {
        _timer?.cancel();
        _timer = null;
        List list = dataList;
        _timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
          for (int i = 0; i < list.length; i++) {
            var tempTime = list[i];
            if (tempTime == 0) {
            } else {
              tempTime -= 1;
            }
            list[i] = tempTime;
          }
          print('哈哈哈哈哈哈哈');
          setState(() {
            dataList = list;
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        /// 写一个下拉刷新的列表 定时器加速问题
        return Scaffold(
          appBar: AppBar(
            title: const Text('定时器使用'),
          ),
          body: EasyRefresh(
            controller: _controller,
            firstRefresh: true,
            header: ClassicalHeader(),
            footer: ClassicalFooter(),
            onRefresh: () async {
              await Future.delayed(const Duration(seconds: 1));
              creatData();
              _controller.resetLoadState();
            },
            child: ListView.builder(
                shrinkWrap: true,
                physics: const AlwaysScrollableScrollPhysics(),
                itemCount: dataList.length,
                itemBuilder: (BuildContext context, int index) {
                  return Container(
                    height: 50,
                    alignment: Alignment.center,
                    margin: const EdgeInsets.only(left: 15, right: 15, top: 15),
                    decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(6),
                        boxShadow: const [
                          BoxShadow(
                              color: Colors.black12,
                              offset: Offset(0.0, 0.0), //阴影xy轴偏移量
                              blurRadius: 2.0, //阴影模糊程度
                              spreadRadius: 2.0 //阴影扩散程度
                          )
                        ]),
                    child: Text(
                      FormatUtils.constructTime(dataList[index]),
                      style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
                    ),
                  );
                }),
          )
        );
      }
    
      @override
      void dispose() {
        // TODO: implement dispose
        super.dispose();
        _timer?.cancel();
        _timer = null;
        _controller.dispose();
      }
    }
    
    

    其实就是声明timer时,这样声明Timer? _timer;startTimer中将上一个timer取消,并置为null,再重新创建一个timer,就解决了这个问题.

    注意点

    一定要记住在dispose中加上下面的代码,不然的话定时器是不会释放,容易引起内存的问题.

    @override
      void dispose() {
        // TODO: implement dispose
        super.dispose();
        _timer?.cancel();
        _timer = null;
        _controller.dispose();
      }
    

    到此我们就可以很愉快的使用定时器了,纯属技术交流,不喜勿喷,欢迎评论交流.

    demo地址请移步: 项目地址
    Flutter TabBar 在实际项目中的运用: 项目地址

    相关文章

      网友评论

        本文标题:Flutter timer的使用

        本文链接:https://www.haomeiwen.com/subject/gdntzrtx.html