Flutter中使用setState时的6个简单技巧总结

目录
  • 前言
  • setState 有什么用?
  • 技巧 1:保持## widgets小!
  • 技巧 2:不要在构建方法中调用 setState
  • 技巧 3:不要在 initState 方法中调用 setState
  • 技巧4:setState()和setState(...)是相等的
  • 技巧 5:setState(...) 代码必须很小
  • 技巧 6:setState(...) 代码不能是异步的
  • 结束

前言

setState 函数是在 Flutter 应用程序中管理状态的最基本方法。以下是一些保持应用可维护性的最佳实践。

StatefulWidget 的 setState 函数是一种在 Flutter 应用程序中管理状态的简单方法。但是,当您希望您的应用程序正常工作和高性能时,您需要避免几个陷阱。以下是您应该坚持的一些最佳实践。

setState 有什么用?

setState 是Flutter发出 rebuild (重建)当前 widget 及其后代的方式。在 rebuild 过程中,最新的变量值将被用于创建用户界面。比方说,一个用户将一个开关从打开切换到关闭。该开关有一个存储该值的支持变量,所以在改变之后,它被设置为 false。开关本身并不反映这一变化,直到它被重建为新的支持字段值。

  • 更改值
  • 调用 setState()
  • 用户界面已更新

技巧 1:保持## widgets小!

setState 触发了对你当前所在的小组件的重建。如果你的整个应用程序只包含一个widget,那么整个widget将被重建,这将使你的应用程序变得缓慢。请看下面的例子。

import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  @override
  State<Home> createState() => _State();
}

class _State extends State<Home> {
  bool _tile1 = false;
  bool _tile2 = false;
  bool _tile3 = false;
  bool _tile4 = false;
  bool _tile5 = false;

  @override
  Widget build(BuildContext context) {
    print("built method Home"); // <-- setState triggers build here!
    return Scaffold(
        appBar: AppBar(title: const Text("Demo")),
        body: Center(
            child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
              SwitchListTile(
                  activeColor: Colors.green,
                  inactiveThumbColor: Colors.red,
                  title: Text("Switch is ${_tile1 ? "on" : "off"}"),
                  value: _tile1,
                  onChanged: (_) {
                    setState(() {
                      _tile1 = !_tile1;
                    });
                  }),
              SwitchListTile(
                  activeColor: Colors.green,
                  inactiveThumbColor: Colors.red,
                  title: Text("Switch is ${_tile2 ? "on" : "off"}"),
                  value: _tile2,
                  onChanged: (_) {
                    setState(() {
                      _tile2 = !_tile2;
                    });
                  }),
              SwitchListTile(
                  activeColor: Colors.green,
                  inactiveThumbColor: Colors.red,
                  title: Text("Switch is ${_tile3 ? "on" : "off"}"),
                  value: _tile3,
                  onChanged: (_) {
                    setState(() {
                      _tile3 = !_tile3;
                    });
                  }),
              SwitchListTile(
                  activeColor: Colors.green,
                  inactiveThumbColor: Colors.red,
                  title: Text("Switch is ${_tile4 ? "on" : "off"}"),
                  value: _tile4,
                  onChanged: (_) {
                    setState(() {
                      _tile4 = !_tile4;
                    });
                  }),
              SwitchListTile(
                  activeColor: Colors.green,
                  inactiveThumbColor: Colors.red,
                  title: Text("Switch is ${_tile5 ? "on" : "off"}"),
                  value: _tile5,
                  onChanged: (_) {
                    setState(() {
                      _tile5 = !_tile5;
                    });
                  })
            ])));
  }
}

这里我们在一个 Column 中有 5 个 SwitchListTile 小部件,它们都是同一个小部件的一部分。

如果您切换任何控件,整个屏幕都会被重建。 Scaffold, AppBar, Column, ... 但只要重建已更改的小部件就足够了。让我们看下一个代码示例:

import 'package:flutter/material.dart';

class Home2 extends StatefulWidget {
  const Home2({Key? key}) : super(key: key);

  @override
  State<Home2> createState() => _State();
}

class _State extends State<Home2> {
  @override
  Widget build(BuildContext context) {
    print("built method Home2");
    return Scaffold(
        appBar: AppBar(title: const Text("Demo")),
        body: Center(
            child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.center,
                children: const <Widget>[
              Switch(),
              Switch(),
              Switch(),
              Switch(),
              Switch()
            ])));
  }
}

class Switch extends StatefulWidget {
  const Switch({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _SwitchState();
}

class _SwitchState extends State<Switch> {
  bool _value = false;

  @override
  Widget build(BuildContext context) {
    print("build method Switch"); // <-- setState triggers build here!
    return SwitchListTile(
        activeColor: Colors.green,
        inactiveThumbColor: Colors.red,
        title: Text("Switch is ${_value ? "on" : "off"}"),
        value: _value,
        onChanged: (_) {
          setState(() {
            _value = !_value;
          });
        });
  }
}

在这里,我们将 SwitchListTile 包装在单个 StatefulWidget 中。页面看起来相同,但如果您单击此示例中的任何开关,则只有单击的小部件将重建。

技巧 2:不要在构建方法中调用 setState

来自 Flutter API 文档

这个方法有可能在每一帧中被调用,除了建立一个小部件外,不应该有任何副作用。

build 方法旨在构建小部件树,因此我们应该保持这种方式。不要在这里做花哨的事情,它会减慢你的应用程序。对setState的调用可能会触发额外的重建,在最坏的情况下,你可能最终会出现一个异常,告诉你目前有一个重建正在进行。

技巧 3:不要在 initState 方法中调用 setState

initState 将在完成后触发重建,因此无需在此方法中调用 setState。此方法旨在初始化与状态相关的属性,例如设置默认值或订阅流。不要在这里做任何其他事情!

技巧4:setState()和setState(...)是相等的

像这样使用 setState 没关系

setState((){
  _text = “Hello”;
});

或者像这样

_text = “Hello”;
setState((){});

结果是一样的。

技巧 5:setState(...) 代码必须很小

不要在setState内做任何大的计算,因为它将阻止你的应用程序重绘。请看下面的示例代码:

setState(() {
  for (var i = 0; i < 10000; i++) print(i);
  _value = true;
});

只有在打印语句之后,小部件才会重建。在这段时间里,你的应用程序不会对用户的操作做出反应,它将在之后执行这些操作。因此,如果用户因为没有视觉反馈而多次点击一个控件,多次重建就会堆积起来,会使应用程序的速度更慢。

一个更好的方法是在执行一个长期运行的操作时显示一个进度指示器,这样用户就知道正在发生一些事情,他需要等待完成。

技巧 6:setState(...) 代码不能是异步的

运行代码时

setState(() async {
  await Future.delayed(const Duration(seconds: 5));
});

你最终会得到一个类似这样的异常信息:

在方法之外执行异步操作,然后调用它。

结束

我希望这些见解能帮助你更好地理解Flutter中setState的机制。坚持这些技巧,你会有更少的问题和更快的应用程序。源代码例子可以在GitHub上找到。

到此这篇关于Flutter中使用setState时的6个简单技巧的文章就介绍到这了,更多相关Flutter使用setState的技巧内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Flutter开发setState能否在build中直接调用详解

    目录 两种情况 原理分析 总结 两种情况 setState() 能在 build() 中直接调用吗?答案是能也不能. 来看一段简单的代码: import 'package:flutter/material.dart'; class TestPage extends StatefulWidget { const TestPage({super.key}); @override State<TestPage> createState() => _State(); } class _State

  • Flutter改变状态变量是否必须写在setState回调详解

    正文 我们都知道 setState(VoidCallback fn) 是这样用的: setState(() { count++; }); 执行完后组件会重新 build(),就可以取到 count 的最新值了.但其实这样写也是一样的: count++; setState(() {}); 因为 setState() 最后会调用 markNeedsBuild(),Flutter 会调度使组件 rebuild,所以状态变量的改变不是必须写在 setState() 的回调里面,只需要最后执行一下 set

  • Flutter中使用setState时的6个简单技巧总结

    目录 前言 setState 有什么用? 技巧 1:保持## widgets小! 技巧 2:不要在构建方法中调用 setState 技巧 3:不要在 initState 方法中调用 setState 技巧4:setState()和setState(...)是相等的 技巧 5:setState(...) 代码必须很小 技巧 6:setState(...) 代码不能是异步的 结束 前言 setState 函数是在 Flutter 应用程序中管理状态的最基本方法.以下是一些保持应用可维护性的最佳实践.

  • flutter中的布局和响应式app方法示例

    目录 flutter中的布局 (使用)放置一个组件 app 本身就是个组件 Material apps 和 Non-Material apps 自适应和响应式 flutter实现响应式的方法 小结 flutter中的布局 flutter布局机制的核心是组件.在flutter中,几乎所有的东西都是组件,布局模型也不例外.图片,Icon, 文本等等,我们在flutter客户端中看到的所有内容都是组件.我们看不到的东西,比如:rows,columns,等等等等也都是组件. 我们将简单的组件组合在一起,

  • Flutter中网络图片加载和缓存的实现

    前言 应用开发中经常会碰到网络图片的加载,通常我们会对图片进行缓存,以便下次加载同一张图片时不用再重新下载,在包含有大量图片的应用中,会大幅提高图片展现速度.提升用户体验且为用户节省流量.Flutter本身提供的Image Widget已经实现了加载网络图片的功能,且具备内存缓存的机制,接下来一起看一下Image的网络图片加载的实现. 重温小部件Image 常用小部件Image中实现了几种构造函数,已经足够我们日常开发中各种场景下创建Image对象使用了. 有参构造函数: Image(Key k

  • flutter 中监听滑动事件

    在移动端,各个平台或 UI 系统的原始指针事件模型基本都是一致,即:一次完整的事件分为三个阶段:手指按下.手指移动.和手指抬起,而更高级别的手势(如点击.双击.拖动等)都是基于这些原始事件的. Flutter 中可以使用 Listener widget 来监听原始触摸事件,它也是一个功能性 widget. Listener 的常见属性 属性 类型 说明 onPointerDown (PointerDownEvent event){} 手指按下时触发 onPointerMove (PointerD

  • Flutter中嵌入Android 原生TextView实例教程

    前言 本篇文章 中写到的是 flutter 调用了Android 原生的 TextView 案例 添加原生组件的流程基本上可以描述为: 1 android 端实现原生组件PlatformView提供原生view 2 android 端创建PlatformViewFactory用于生成PlatformView 3 android 端创建FlutterPlugin用于注册原生组件 4 flutter 平台嵌入 原生view 1 创建原生组件 创建在fLutter工程时会生成几个文件夹,lib是放fl

  • 详解Flutter中视频播放器插件的使用教程

    目录 创建一个新的视频播放器 添加播放和暂停按钮 创建一个快进 添加一个视频进度指示器 应用视频的字幕 结论 您已经看到很多包含视频内容的应用程序,比如带有视频教程的食谱应用程序.电影应用程序和体育相关的应用程序.您是否想知道如何将视频内容添加到您的下一个Flutter应用程序中? 从头开始实现视频功能将是一项繁重的任务.但有几个插件可以让开发者的生活变得轻松.视频播放器插件是可用于 Flutter 的最佳插件之一,可满足这一要求. 在这篇文章中,您将学习如何应用视频播放器插件以及控制视频播放器

  • 详解如何在Flutter中获取设备标识符

    目录 使用 platform_device_id 应用预览 代码 使用 device_info_plus 应用预览 代码 结论 本文将引导您完成 2 个示例,演示如何在 Flutter 中获取设备标识符 使用 platform_device_id 如果您只需要运行应用程序的设备的 id,最简单快捷的解决方案是使用platform_device_id包.它适用于 Android (AndroidId).iOS (IdentifierForVendor).Windows (BIOS UUID).ma

  • 详解Flutter中的数据传递

    目录 Flutter 中的数据传递 InheritedWidget EventBus 总结 Flutter 中的数据传递 在开发中,数据从一个页面传递到另一个页面事很常用的,在Android 开发中,通常是通过把数据放到 intent 中传递过去.在 Flutter 中,数据是如何传递的呢? 在Flutter 中一切都是Widget,所以数据的传递就成了数据才Widget 中的传递.在之前的学习中,数据从一个Widget 传递到 子 Widget 是通过构造函数,一层一层的往里面传,要是 wid

  • js 交互在Flutter 中使用 webview_flutter

    目录 正文 环境准备 最简示例 WebView 的小大 网页自己报告高度 无法修改页面 在网页中调用 Flutter 页面 拦截 url js 调用 JavaScriptChannel 定义的方法 总结 正文 已经有很多关于 Flutter WebView 的文章了,为什么还要写一篇.两个原因: Flutter WebView 是 Flutter 开发的必备技能 现有的文章都是关于老版本的,新版本 4.x 有了重要变化,基于 3.x 的代码很多要重写. WebView 的文章分两篇 在 Flut

  • Flutter中http请求抓包的完美解决方案

    前言 前阵子有同学反馈Flutter中的http请求无法通过fiddler抓包,作者喜欢使用Charles抓包工具,于是抽时间写了个小demo测试了一下,结论是在手机上设置代理,Charles确实抓不到请求数据包.于是对该问题进行了分析: 确定使用的是http发起的get请求,理论上http协议应该可以被Charles抓到包的,如果没有抓到包,那可能是没有走代理,于是乎通过将笔记本连接的wifi断开测试了一下手机上APP发起http请求,发现请求成功,证实确实没有走代理: 为什么http请求没有

随机推荐