用前端最舒服的躺姿 "搞定" Flutter

简介: 当下最火的跨端技术,当属于 Flutter ,应该没人质疑吧。一个新的技术的趋势,最明显的特征,就是它一定想把“前浪”拍死在沙滩上。这个前浪,就是"react Native","weex"。目前随便在搜索引擎上 搜索"Flutter reactNative",就全是这两个技术的对比,评测。

原创 朱炎(一晟) 淘系技术  2020-08-06


前言



image.png


一股股浓浓 : 不服来 “掰” 啊 !!!的味道。


是的,错过了react Native, weex 这些 “炸” 翻前端的技术,不能在错过 Flutter 了,这年头,你不会一门跨端技术,怎么好意思说自己是【前端】。


image.png


2020年5月,Flutter 团队带来了的第一个稳定版本,Flutter 1.17.x 版。


按照官方的说法,新版本关闭了自Flutter 1.12版本的6,339个问题,从231位贡献者那里合并了3164个PR,并修复了许多错误。除了质量改进之外,新版本还在增加了一些新功能:


  • 移动性能和应用程序包大小的改进


运行速度将提高20%-37%,iOS动画减少40%的CPU / GPU使用率;Flutter Gallery示例,包大小减少了18.5%,快速滚动浏览大图像时,减少了70%的内存。


  • Metal对iOS性能提升50%


开发者可以使用 Metal API直接访问底层 GPU , iOS 设备上,Flutter 将默认使用 Metal,使得应用在绝大多数情况下都运行得更快,渲染速度平均提升约 50%。


  • 新的Material Widget


这是一个新的 widget NavigationRail组件,它由 Google Material Design 团队设计并实现。 NavigationRail 非常适合在移动和桌面设备之间切换的应用。还增加了新的 Animations 库,提供了实现新的 Material motion规范的预构建动画。


  • Dart DevTools for Flutter


这是一个神器,用过chrome DevTools 的一定不陌生,Dart DevTools 用于 Dart 和 Flutter 代码调试和性能分析的工具。这套工具集功能非常全,包含性能、UI、热更新、热重载、log日志等很多功能。(这个工具以后会专门一期介绍)。


  • 新的Flutter文本主题和Google字体


在新版本中,Flutter 团队在不破坏现有 Flutter 应用的同时,完成了对 2018 年 Material Design 规范文字排版缩放 (Type Scale) 的实现。也就是说TextTheme API是向前兼容的,对于旧的废弃名称只做警告。同时新的 主题也可以搭配 新的Google Fonts for Flutter v1.0 字体。


  • 无障碍功能和国际化


更加全面的工作,对滚动、文本框以及其他输入 widget 的无障碍功能进行了修复。GitHub 上有在这个版本中完成修复的无障碍功能完整列表。国际化方面, 完成了三星键盘输入法的bug。


  • 其他重要改动


在使用 pushReplacement 时,保留之前的路径,继续执行动画
弃用 UpdateLiveRegionEvent
在高速滚动时延迟图像解码
文本选取溢出bug (Android)
空绘图对象的断言缓存提示设置
实时图像缓存
可视范围内,确保构造块高度计算选区准确
在gen_l10n中生成消息查询
从RouteSettings中移除isinitialroute
将mouse_tracking.dart移动到rendering


具体细节可以参考官方地址:https://medium.com/flutter/flutter-spring-2020-update-f723d898d7af


每次迭代都有令人小激动的改进,但是对于刚接触 Flutter 的 web 前端同学来说还是......


image.png


好了,回到标题,笔者作为一名传统 web前端,想从前端最熟悉的视角 “躺” 着把 Flutter 了解一遍,不要敬仰,平视它!!!先从兴趣开始。


image.png



正文



Flutter 环境的搭建,其实有很多资源可以参考。这里就不赘述了(知道有很多坑,在后续文章中,有机会把个人遇到的坑汇总一下 )。


有兴趣可以参考 「flutter安装环境的搭建」(https://flutter.cn/docs/get-started/install/macos)  , 在这里建议各位,一定要自己亲自搭一下环境,跑一下官方demo, 小马过河,焉知深浅,自己定的位才是最准确的。


有了环境,「配置编辑器」 (https://flutter.cn/docs/get-started/editor)


然后「创建一个Flutter项目」(https://flutter.cn/docs/get-started/codelab)


项目创建完成,可以先用 flutter run 跑一下。




flutter doctor // 让 flutter 医生检查一下环境和配置,得到四个 ☑ 后,恭喜你通过考核。
flutter run // 奔跑吧...


好了,跑起来了吧,你会看到一个计数的官方示例,点击加号图片可以做加运算。


这时候我们看项目的project 目录里 有一个入口文件叫 main.dart。然后打开 main.dart 就像下面这样:


image.png


( 为什么你们看到代码比我的长,因为我折叠了!!! ) 这不是重点,重点是每个类继承的都是一个尾号为Widget 的字符。


聪明的你一定会觉得 Widget 和 Flutter 有着某种神秘的联系。


“Binggo!",是的,Flutter 有两个重型武器,一个叫 Dart ,另一个就是 Widget 了。


Dart 一切皆来自 Object, Flutter 的组件皆来自 Widget。


关于强大的Dart,今天暂且不表,后面有时间可以独立篇幅来聊聊Dart。


先祭出一张 Flutter 的架构老图。


image.gifimage.png


在 Flutter 的世界里,包括views,view controllers,layouts等在内的概念都建立在Widget之上。


Widget 是 Flutter 组件的抽象描述。所以掌握Flutter的基础就是学会使用 Widget开始。


在Flutter界面渲染过程分为三个阶段:布局、绘制、合成,布局和绘制在Flutter框架中完成,合成则交由引擎负责:


image.png

Flutter 通过组合、嵌套不同类型的控件,就可以构建出任意功能、任意复杂度的界面。


  • 它包含的最主要的几个类有:


class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding,PaintingBinding, RendererBinding, WidgetsBinding { ... }
abstract class Widget extends DiagnosticableTree { ... }
abstract class StatelessWidget extends Widget { ... }
abstract class StatefulWidget extends Widget { ... }
abstract class RenderObjectWidget extends Widget { ... }
abstract class Element extends DiagnosticableTree implements BuildContext { ... }
abstract class RenderObjectElement extends Element { ... }
class StatelessElement extends ComponentElement { ... }
class StatefulElement extends ComponentElement { ... }


上面这些类的主要作用如下:

  • 基于Flutter控件系统开发的程序都需要使用WidgetsFlutterBinding,它是Flutter的控件框架和Flutter引擎的胶水层。
  • Widget就是所有控件的基类,它本身所有的属性都是只读的。
  • RenderObjectWidget所有的实现类则负责提供配置信息并创建具体的RenderObjectElement。
  • Element是Flutter用来分离控件树和真正的渲染对象的中间层,控件用来描述对应的element属性,控件重建后可能会复用同一个element。
  • RenderObjectElement持有真正负责布局、绘制和碰撞测试(hit test)的RenderObject对象。
  • StatelessWidget和StatefulWidget并不会直接影响RenderObject创建,只负责创建对应的RenderObjectWidget
  • StatelessElement和StatefulElement也是类似的功能。

很复杂是吧,先不用管,简单表述Widget是这样的:


Widget = 样式(css) + 标记语义(标签) + 组件化(官方) + 数据绑定(props)


“什么?这不就是 react 吗?"


对, React 的概念和 Flutter 的 Widget 是有相通性的。


“既然有react的概念,难道还有state,setState吗?“


又对, Flutter 还真有 类似 state 状态机制的概念,而且也确实有 setState 的方法。


“dome里有两个基类,StatelessWidget 和 StatefulWidget 是做什么用的?”


StatelessWidget 和 StatefulWidget,这里两个类特别重要,几乎所有的组件都是基于他们创建的。


StatelessWidget 是状态不可变的widget,称为 无状态widget。初始状态设置以后就不可再变化。如果需要变化需要重新创建。


StatefulWidget 可以保存自己的状态,称为 有状态widget。Flutter 首先保存了初始化时创建的State,状态是通过改变State,来重新构建 Widget 树来进行UI变化。改变状态的方法,就是我们用的最多的神器"setState",而单纯改变数据是不会引发UI改变的,这个概念和我们的 React 一样一样的。


如果你是初次接触 Flutter 可以不用记忆这么多组件基类,只用记住以下式子就可以, 不夸张的说,熟悉这个式子就可以开发 Flutter 项目了:


image.png


拆解



围绕着widget的构成,我们来拆解分析一下,标记语义,样式,组件化。



 标记语义


为什么不称为 “模版”,“标签”,“element" ,而叫"标记语义",是因为flutter的 widget 结构并不只是 “模版”,“标签”,“element"。widget 描述结构更像是 React 的虚拟dom阶段,浓缩了相关上下文,以对象化的结构展示。


我们先来看看,React 创建出来的虚拟dom结构( 伪代码 ):


var newTree = el('div', {'id': 'container'}, [
    el('h1', {style: 'color: red'}, ['simple virtal dom']),
    el('p', ['Hello, virtual-dom']),
    el('ul', [el('li'), el('li')])
])



再来看看,flutter 用Dart 创建的 widget 代码结构:


Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        new Container(
          padding: new EdgeInsets.only(top:100.0),
          child: new Text('这是一个组件')
        ),
        new Container(
          decoration: new BoxDecoration(border: new Border.all(width:1.0,color: Colors.blue)),
          padding: new EdgeInsets.all(20.0),
          child: new Text('来自输入框:'+active)
        )
      ],
    );
  }



是不是这样看就熟悉很多了。


注:很多前端er 会不习惯这中书写方式,目前有开发者在社区推动,在编译前,使用jsx标签,编译后再解析成标记树,比如这个DSX设计的提案。


虽然jsx->标记树 还只是提案,但其实可以帮助我们更容易理解,此提案想表达的样式像这样:


class MyScaffold extends StatelessWidget {
  build(context) {
    return <Material>
      <Column>
          <MyAppBar
             title={<Text 
               text='Example title'
               style={Theme.of(context).primaryTextTheme.title},
             />}
          />
          <Expanded>
            <Center>
              <Text text='Hello, world!'/>
            </Center>
          </Expanded>
      </Column>
    </Material>;
  }
}



上面这段 jsx 要是用 Dart 来写是什么样的?如下:



class MyScaffold extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Material(
      child: Column(
        children: <Widget>[
          MyAppBar(
            title: Text(
              'Example title',
               style: Theme.of(context).primaryTextTheme.title,
            ), // Text
          ), // MyAppBar
          Expanded(
            child: Center(
              child: Text('Hello, world!'),
            ), // Center
          ), // Expanded
        ], // <Widget>[]
      ), // Column
    ); // Material
  }
}



虽然 Flutter 与 react 这么类比多少有些牵强,但可以个人总结一些方法,方便理解:


  • 开头大写的类名 相当于 jsx 的标签名
  • child 相当于 jsx 的 子标签+布局
  • children 相当于 jsx 的 群组子标签(和child还是有区别的)
  • 其他属性相当于 jsx 的 props
  • 大家有没有注意, 第二段dart 语法结尾都会带上 “ // ” 注释符号,这个是编辑器IDE在识别是 Flutter 项目后,自动追加上去的,像 jsx 语言的标签封闭,方便发现标注的起始节点。


 样式


对于 Flutter 样式的理解,可以查看官方的这篇文档,也是同样用类比的方式,很直观的了解,HTML、css样式和 flutter 之间的联系。


https://flutterchina.club/web-analogs/


笔者摘选其中样例的重点部分,对比展示来说明( 由于篇幅问题, 父子关系css 结构,用tab方式来表示 ):


文本样式:


.demo1 {
      background-color: #e0e0e0;
      width: 320px;
      height: 240px;
      font: 900 24px Georgia;
      letter-spacing: 4px; 
      text-transform: uppercase; 
    }

var demo1 = new Container( 
  child: new Text(
    "Lorem ipsum".toUpperCase(), // 对应 左边的文本转换大小写
    style: new TextStyle( // 对应 左边的 font
      fontSize: 24.0
      fontWeight: FontWeight.w900,
      fontFamily: "Georgia",
      letterSpacing: 4.0, 
    ),
  ),
  width: 320.0,  // 对应 左边的 width
  height: 240.0,  // 对应 左边的 height
  color: Colors.grey[300],  // 对应 左边的 background-color
);



样式居中:


.demo2 {
      display: flex;
      align-items: center;
      justify-content: center; 
    }



var demo2 = new Container(
  child:  new Center( // 对应左边的整个 flex 属性
    child:  new Text("Lorem ipsum")
   )
  );
);


设置最大(小)宽度:


.container{
   width:300px
   .demo3 {
      width: 100%;
      max-width: 240px; 
   }
  }


// 对于嵌套容器,如果父级的宽度小于子级宽度,则子级容器将自行调整大小以匹配父级。
var container = new Container(
   child: new Center(
        child: new Text("Lorem ipsum"),
        decoration: new BoxDecoration( ... ), // constraints属性,创建一个新的BoxConstraints来设置minWidth或maxWidth
        width: 240.0, // 对应左边的 max-width
    ),
   width:300.0
  ),


旋转组件:

 .redbox {
       transform: rotate(15deg); 
 }



var container = new Container( // gray box
    child:  new Transform( // 对应左边的 transform
      child:  new Container(  ... ),
      alignment: Alignment.center, // 对应左边的 transform
      transform: new Matrix4.identity() // 对应左边的 transform
        ..rotateZ(15 * 3.1415927 / 180),
    ), 
  )
);


缩放组件:


.redbox {
  transform: scale(1.5); 
}



var container = new Container( // gray box
    child:  new Transform( // 对应左边的 transform
      child:  new Container(  ... ),
      alignment: Alignment.center, // 对应左边的 transform的中心
      transform: new Matrix4.identity() // 对应左边的 transform
        ..scale(1.5),
    ), 
  )
);


设置绝对位置和相对位置:


.greybox {
     position: relative; 
     .redbox {
       position: absolute;
       top: 24px;
       left: 24px; 
     }
}



var container = new Container( // grey box
  child: new Stack( // 相对跟容器位置 relative
    children: [
      new Positioned( // 相对父容器位置 absolute
        child:  new Container( ... ),
        left: 24.0,
        top: 24.0,
      )],
  )
);


颜色渐变:



.redbox {
  background: linear-gradient(180deg, #ef5350, rgba(0, 0, 0, 0) 80%); 
}



var container = new Container( // grey box
  child: new Center(
    child: new Container( // red box
      child: new Text( ... ),
      decoration: new BoxDecoration( 
        gradient: new LinearGradient( // 对应左边的 background: linear-gradient
          begin: const Alignment(0.0, -1.0),
          end: const Alignment(0.0, 0.6),
          colors: [
            const Color(0xffef5350),
            const Color(0x00ef5350)
          ],
        ),
      )
    ),
  )
);


圆角:


.redbox {
  border-radius: 8px; 
}

var container = new Container( // grey box
  child: new Center(
    child: new Container( // red circle
      child: new Text( ... ),
      decoration: new BoxDecoration(
        borderRadius: new BorderRadius.all(
          const Radius.circular(8.0),
        ), 
      )
    ),
  )
);


阴影:


.redbox {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.8),
              0 6px 20px rgba(0, 0, 0, 0.5);
}

var container = new Container( // grey box
  child: new Center(
    child: new Container( // red box
      child: new Text( ... ),
      decoration: new BoxDecoration(
        boxShadow: [ // 对应左边的  box-shadow
          new BoxShadow (
            color: const Color(0xcc000000),
            offset: new Offset(0.0, 2.0),
            blurRadius: 4.0,
          ),
          new BoxShadow (
            color: const Color(0x80000000),
            offset: new Offset(0.0, 6.0),
            blurRadius: 20.0,
          ),
        ], 
      )
    ),
  )
);


画圆:



.redcircle {
  text-align: center;
  width: 160px;
  height: 160px;
  border-radius: 50%; 
}

var container = new Container( // grey box
  child: new Center(
    child: new Container( // red circle
      child: new Text( ... ),
      decoration: new BoxDecoration(
        color: Colors.red[400],
        shape: BoxShape.circle, // 画圆和圆角不太一样,用的是BoxShape绘制图像能力
      ),
      width: 160.0,
      height: 160.0, 
    ),
  )
);


内联样式:


// css 的内联结构
.greybox {
    font: 900 24px Roboto; 
   .redbox {
       em {
          font: 300 48px Roboto;
          font-style: italic;
      }
    } 
}

var container = new Container( // grey box
  child: new Center(
    child: new Container( // red box
      child:  new RichText(
        text: new TextSpan(
          style: bold24Roboto,
          children: [
            new TextSpan(text: "Lorem "), // 继承内联样式
            new TextSpan(
              text: "ipsum",
              style: new TextStyle( // 具有自定义样式的单独样式
                fontWeight: FontWeight.w300,
                fontStyle: FontStyle.italic,
                fontSize: 48.0,
              ),
            ),
          ],
        ),
      ),
    ),
  )
);



组件化



官方的widgets目录



image.png



点击每一个card后,里面还有子card, 以一个展开的纬度来看,是这样的:



这真是一个庞大的组件系统,这不是社区提供的,而是官方的。


flutter 团队事无巨细的实现了目前市面上基本上能见到的组件方式和类型。
个人认为这样做优缺点并存的。


先说缺点:


  • 1.学习成本增加,曲线也还是比较陡的。
  • 2.组件直接的继承关系路径比较零乱,比如
    继承自 Widget 是这些大类道还清晰:
    PreferredSizeWidget ProxyWidget RenderObjectWidget StatefulWidget StatelessWidget。
    但是,StatelessWidget和StatefulWidget的子类就过于平行化了,名称上晦涩,没有抽象架构化,分层或者塔型级别。

StatelessWidget:

StatefulWidget

  • 3.对自定义组件定义模糊,有这么庞大的组件库,到底以后是有个一个更系统的第三方组件库去替换它,还是说 Flutter 官方就不建议使用第三方组件,这个也未有定论。


再说优点:


  • 1.可以阻止以后轮子泛滥,在团队僵持不下使用哪个轮子库时,最好的理由就是“官方”二字,因为使用官方,可以弱化和规避一些问题,比如: 版本迭代不同步,性能瓶颈,规范不统一等问题,也能快速支持官方的辅助工具。
  • 2.正是由于官方的标准划一,为自动化编译,自动化搭建,测试调优,可视化带来便利,甚至为Ai前端模型化业务场景,提供支撑,都说前端的组件像搭乐高,Flutter就是颗粒标准统一的乐高。
  • 3.天下之势,分久必合,合久必分。

  • 前端在经历了 flash 一统pc页面的富媒体时代,后被乔布斯和H5瓦解;
  • 之后又有H5 的繁盛和框架、语法、构建模式的乱战;
  • 再到有“别再更新,老子学不动"的呼声下,希望有个一统江湖的跨平台系统出现;
  • 让开发者更专注于,提高业务内容,创造 “新, 酷,炫” 的展现形势上下功夫。
  • 也许,真有一个前端江湖的王者的诞生。



最后



实际的 Flutter Widget 要复杂的更多的多,在眼花缭乱的 Widget 组件中,笔者想用自己的一些理解,去粗取精,来逐步理解 Flutter 这个新家伙 ,文中有理解不到位的地方,欢迎大家指正。笔者团队也正在开发一套《Flutter 菜鸟手册》的APP,帮助大家熟悉复杂的 Flutter Widget。


原文链接(https://github.com/ryan730/PersonalBlog/issues/1


更多学习 Flutter的小伙伴,欢迎入QQ群 Flutter Go :679476515


《Flutter GO》项目地址 [alibaba/flutter-go](https://github.com/alibaba/flutter-go) 或点击阅读原文



相关文章
|
6月前
|
缓存 监控 前端开发
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
【4月更文挑战第30天】本文探讨了Flutter应用启动优化策略,包括理解启动过程、资源加载优化、减少初始化工作、界面布局简化、异步初始化、预加载关键数据、性能监控分析以及案例和未来优化方向。通过这些方法,可以缩短启动时间,提升用户体验。使用Flutter DevTools等工具可助于识别和解决性能瓶颈,实现持续优化。
259 0
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
|
6月前
|
Dart 前端开发 安全
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
【4月更文挑战第30天】本文探讨了Flutter中线程管理和并发编程的关键性,强调其对应用性能和用户体验的影响。Dart语言提供了`async`、`await`、`Stream`和`Future`等原生异步支持。Flutter采用事件驱动的单线程模型,通过`Isolate`实现线程隔离。实践中,可利用`async/await`、`StreamBuilder`和`Isolate`处理异步任务,同时注意线程安全和性能调优。参考文献包括Dart异步编程、Flutter线程模型和DevTools文档。
202 1
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
|
6月前
|
Dart 前端开发 测试技术
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
【4月更文挑战第30天】随着Flutter在跨平台开发的普及,保证代码质量成为开发者关注的重点。优质代码能确保应用性能与稳定性,提高开发效率。关键策略包括遵循最佳实践,编写可读性强的代码,实施代码审查和自动化测试。重构实践在项目扩展时尤为重要,适时重构能优化结构,降低维护成本。开发者应重视代码质量和重构,以促进项目成功。
78 0
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
|
6月前
|
存储 缓存 监控
【Flutter前端技术开发专栏】Flutter中的列表滚动性能优化
【4月更文挑战第30天】本文探讨了Flutter中优化列表滚动性能的策略。建议使用`ListView.builder`以节省内存,避免一次性渲染所有列表项。为防止列表项重建,可使用`UniqueKey`或`ObjectKey`。缓存已渲染项、减少不必要的重绘和异步加载大数据集也是关键。此外,选择轻量级组件,如`StatelessWidget`,并利用Flutter DevTools监控性能以识别和解决瓶颈。持续测试和调整以提升用户体验。
193 0
【Flutter前端技术开发专栏】Flutter中的列表滚动性能优化
|
6月前
|
存储 缓存 前端开发
【Flutter前端技术开发专栏】Flutter中的图片加载与缓存优化
【4月更文挑战第30天】本文探讨了 Flutter 中如何优化图片加载与缓存,以提升移动应用性能。通过使用图片占位符、压缩裁剪、缓存策略(如`cached_network_image`插件)以及异步加载和预加载图片,可以显著加快加载速度。此外,利用`FadeInImage`、`FutureBuilder`和图片库等工具,能进一步改善用户体验。优化图片处理是提升Flutter应用效率的关键,本文为开发者提供了实用指导。
579 0
【Flutter前端技术开发专栏】Flutter中的图片加载与缓存优化
|
6月前
|
Dart 前端开发 开发者
【Flutter前端技术开发专栏】Flutter中的性能分析工具Profiler
【4月更文挑战第30天】Flutter Profiler是用于性能优化的关键工具,提供CPU、GPU、内存和网络分析。它帮助开发者识别性能瓶颈,如CPU过度使用、渲染延迟、内存泄漏和网络效率低。通过实时监控和分析,开发者能优化代码、减少内存占用、改善渲染速度和网络请求,从而提升应用性能和用户体验。定期使用并结合实际场景与其它工具进行综合分析,是实现最佳实践的关键。
321 0
【Flutter前端技术开发专栏】Flutter中的性能分析工具Profiler
|
6月前
|
前端开发 数据处理 Android开发
【Flutter 前端技术开发专栏】Flutter 中的调试技巧与工具使用
【4月更文挑战第30天】本文探讨了Flutter开发中的调试技巧和工具,强调其在及时发现问题和提高效率上的重要性。介绍了基本的调试方法如打印日志和断点调试,以及Android Studio/VS Code的调试器和Flutter Inspector的使用。文章还涉及调试常见问题的解决、性能和内存分析等高级技巧,并通过实际案例演示调试过程。在团队协作中,有效调试能提升整体开发效率,而随着技术发展,调试工具也将持续进化。
87 0
【Flutter 前端技术开发专栏】Flutter 中的调试技巧与工具使用
|
6月前
|
Dart 前端开发 开发者
【Flutter前端技术开发专栏】Flutter中的热重载与热更新机制
【4月更文挑战第30天】Flutter框架提供热重载(Hot Reload)和热更新(Hot Restart)功能,加速开发和迭代。热重载在应用运行时实时应用代码更改,保持应用状态,适合快速查看效果;热更新则重新启动应用,适用于更广泛的变化,但仍比冷启动快。开发者可通过`flutter run`命令或快捷键触发这两项功能。然而,应注意代码兼容性、性能影响及不支持的更改。这两机制提升开发效率,优化用户体验。
705 0
【Flutter前端技术开发专栏】Flutter中的热重载与热更新机制
|
6月前
|
Dart 前端开发 Java
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决
【4月更文挑战第30天】本文探讨了Flutter应用中的内存泄漏检测与解决方法。内存泄漏影响性能和用户体验,常见原因包括全局变量、不恰当的闭包使用等。开发者可借助`observatory`工具或`dart_inspector`插件监测内存使用。解决内存泄漏的策略包括避免长期持有的全局变量、正确管理闭包、及时清理资源、妥善处理Stream和RxDart订阅、正确 disposal 动画和控制器,以及管理原生插件资源。通过这些方法,开发者能有效防止内存泄漏,优化应用性能。
366 0
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决
|
6月前
|
Web App开发 前端开发 iOS开发
CSS3 转换,深入理解Flutter动画原理,前端基础图形
CSS3 转换,深入理解Flutter动画原理,前端基础图形