如何提高Flutter应用程序的性能,Android学习教程

class ConstDemo extends StatefulWidget {

@override

_ConstDemoState createState() => _ConstDemoState();

}

class _ConstDemoState extends State {

@override

Widget build(BuildContext context) {

return Center(

  child: Column(

    children: [

      Text('老孟'),

      RaisedButton(onPressed: (){

        setState(() {



        });

      })

    ],

  ),

);

}

}




![](https://img-blog.csdnimg.cn/img_convert/13bb0c97952d4ed616d43aa59eea21c3.png)



给 **Text('老孟')** 组件加上 **const**:



const Text(‘xx’),




![](https://img-blog.csdnimg.cn/img_convert/e2304527bbf78ca495bcf64bc36f0684.png)



对比两次 **Text** 组件的重建情况,加上 **const** 后,未重建。



避免更改组件树的结构和组件的类型

----------------



有如下场景,有一个 **Text** 组件有可见和不可见两种状态,代码如下:



bool _visible = true;

@override

Widget build(BuildContext context) {

return Center(

child: Column(

  children: [

    if(_visible)

      Text('可见'),

    Container(),

  ],

),

);

}

复制代码




可见时的组件树:



![](https://img-blog.csdnimg.cn/img_convert/394ee6ea4d385efd82d50143d2eb34d1.png)



不可见时的组件树:



![](https://img-blog.csdnimg.cn/img_convert/bd25fc6bed2f2da2bdd90646ddd78b03.png)



两种状态组件树结构发生变化,应该避免发生此种情况,优化如下:



Center(

child: Column(

children: [

  Visibility(

    visible: _visible,

    child: Text('可见'),

  ),

  Container(),

],

),

)




此时不管是可见还是不可见状态,组件树都不会发生变化,如下:



![](https://img-blog.csdnimg.cn/img_convert/6b5c090adc381c6ddc766136457e9f7b.png)



还有一种情况是根据不同的条件构建不同的组件,如下:



bool _showButton = true;

@override

Widget build(BuildContext context) {

return Center(

child: Column(

  children: [

    _showButton ? RaisedButton(onPressed: null) : Text('不显示'),

    Container(),

  ],

),

);

}




设置为 **true** 时的组件树结构:



![](https://img-blog.csdnimg.cn/img_convert/a00769dec4b281a2212fe2278dc287c7.png)



设置为 **false** 时的组件树结构:



![](https://img-blog.csdnimg.cn/img_convert/394ee6ea4d385efd82d50143d2eb34d1.png)



看到左侧子节点由 **RaisedButton** 变为了 **Text**。



上面的情况组件树发生了更改,不管是类型发生更改,还是深度发生更改,如果无法避免,那么就将变化的组件树封装为一个 **StatefulWidget** 组件,且设置 **GlobalKey**,如下:



封装变化的部分:



class ChildWidget extends StatefulWidget {

const ChildWidget({Key key}) : super(key: key);

@override

_ChildWidgetState createState() => _ChildWidgetState();

}

class _ChildWidgetState extends State {

bool _showButton = true;

@override

Widget build(BuildContext context) {

return _showButton ? RaisedButton(onPressed: null) : Text('不显示');

}

}




构建:



class ConstDemo extends StatefulWidget {

@override

_ConstDemoState createState() => _ConstDemoState();

}

class _ConstDemoState extends State {

@override

Widget build(BuildContext context) {

return Center(

  child: Column(

    children: [

      ChildWidget(key: GlobalKey(),),

      Container(),

    ],

  ),

);

}

}




虽然通过 **GlobalKey** 提高了上面案例的性能,但我们千万不要乱用 **GlobalKey**,因为管理 **GlobalKey** 的成本很高,所以其他需要使用 **Key** 的地方建议考虑使用 **Key, ValueKey, ObjectKey, 和 UniqueKey**。



关于 **GlobalKey** 的相关说明参考:api.flutter.dev/flutter/wid…



关于ListView 的优化

--------------



ListView是我们最常用的组件之一,用于展示大量数据的列表。如果展示大量数据请使用 **ListView.builder** 或者 **ListView.separated**,千万不要直接使用如下方式:



ListView(

children: [

item,item1,item2,...

],

)




这种方式一次加载所有的组件,没有“懒加载”,消耗极大的性能。



ListView 中 **itemExtent** 属性对动态滚动到性能提升非常大,比如,有2000条数据展示,点击按钮滚动到最后,代码如下:



class ListViewDemo extends StatefulWidget {

@override

_ListViewDemoState createState() => _ListViewDemoState();

}

class _ListViewDemoState extends State {

ScrollController _controller;

@override

void initState() {

super.initState();

_controller = ScrollController();

}

@override

Widget build(BuildContext context) {

return Stack(

  children: [

    ListView.builder(

      controller: _controller,

      itemBuilder: (context, index) {

        return Container(

          height: 80,

          alignment: Alignment.center,

          color: Colors.primaries[index % Colors.primaries.length],

          child: Text('$index',style: TextStyle(color: Colors.white,fontSize: 20),),

        );

      },

      itemCount: 2000,

    ),

    Positioned(

        child: RaisedButton(

      child: Text('滚动到最后'),

      onPressed: () {

        _controller.jumpTo(_controller.position.maxScrollExtent);

      },

    ))

  ],

);

}

}




![](https://img-blog.csdnimg.cn/img_convert/b8c7677e913fe052dcd6d4d8e9cbcf70.png)



耗时在**2秒**左右,加上 **itemExtent** 属性,修改如下:



ListView.builder(

controller: _controller,

itemBuilder: (context, index) {

return Container(

  height: 80,

  alignment: Alignment.center,

  color: Colors.primaries[index % Colors.primaries.length],

  child: Text('$index',style: TextStyle(color: Colors.white,fontSize: 20),),

);

},

itemExtent: 80,

itemCount: 2000,

)




![](https://img-blog.csdnimg.cn/img_convert/78e1bad1feb0aa4500c6510afa4de41d.png)



优化后瞬间跳转到底部。



这是因为不设置 **itemExtent** 属性,将会由子组件自己决定大小,大量的计算导致UI堵塞。



关于 AnimatedBuilder TweenAnimationBuilder 的优化

--------------------------------------------



这里说的是向AnimatedBuilder 、TweenAnimationBuilder 等一类的组件的问题,这些组件都有一个共同点,带有 **builder** 且其参数中有 **child**。



以 AnimatedBuilder 为例,如果 **builder** 中构建的树中包含与动画无关的组件,将这些无关的组件当作 **child** 传递到 **builder** 中比直接在 **builder** 中构建更加有效。



比如下面的代码,直接在 **builder** 中构建子组件:



AnimatedBuilder(

animation: animation,

builder: (BuildContext context, Widget child) {

  return Transform.rotate(

    angle: animation.value,

    child: FlutterLogo(size: 60,),

  );

},

)




优化后的代码:



AnimatedBuilder(

animation: animation,

builder: (BuildContext context, Widget child) {

  return Transform.rotate(

    angle: animation.value,

    child: child,

  );

},

child: FlutterLogo(size: 60,),

)




谨慎地使用一些组件

---------



部分组件一定要谨慎使用,因为这些组件包含一些昂贵的操作,比如 **saveLayer()** 方法。



> 调用saveLayer()会分配一个屏幕外缓冲区。 将内容绘制到屏幕外缓冲区中可能会触发渲染目标切换,这在较早的GPU中特别慢。



另外虽然下面这些组件比较消耗性能,但并不是禁止大家使用,而是谨慎使用,如果有替代方案,考虑使用替代方法。



尤其注意,如果这些组件频繁重建(比如动画的过程),要重点优化。



Clip 类组件

--------



Clip 类组件是常用的裁剪类组件,比如:ClipOval、ClipPath、ClipRRect、ClipRect、CustomClipper。这些组件中都有 **clipBehavior** 属性,不同的值性能是不同的,



/// * [hardEdge], which is the fastest clipping, but with lower fidelity.

/// * [antiAlias], which is a little slower than [hardEdge], but with smoothed edges.

/// * [antiAliasWithSaveLayer], which is much slower than [antiAlias], and should

/// rarely be used.




越往下,速度越慢。



一些简单的圆角组件的设置可以使用 Container 实现:



Container(

  height: 200,

  width: 200,

  decoration: BoxDecoration(

    image:  DecorationImage(

      image: NetworkImage(

          'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl-2.jpg'),

      fit: BoxFit.cover,

    ),

    border: Border.all(

      color: Colors.blue,

      width: 2,

    ),

    borderRadius: BorderRadius.circular(12),

  ),

文末

那么对于想坚持程序员这行的真的就一点希望都没有吗?
其实不然,在互联网的大浪淘沙之下,留下的永远是最优秀的,我们考虑的不是哪个行业差哪个行业难,就逃避掉这些,无论哪个行业,都会有他的问题,但是无论哪个行业都会有站在最顶端的那群人。我们要做的就是努力提升自己,让自己站在最顶端,学历不够那就去读,知识不够那就去学。人之所以为人,不就是有解决问题的能力吗?挡住自己的由于只有自己。
Android希望=技能+面试

CodeChina开源项目地址:https://codechina.csdn.net/m0_60958482/android_p7

  • 技能

  • 面试技巧+面试题
    -api-docs/assets/widgets/owl-2.jpg’),

        fit: BoxFit.cover,
    
      ),
    
      border: Border.all(
    
        color: Colors.blue,
    
        width: 2,
    
      ),
    
      borderRadius: BorderRadius.circular(12),
    
    ),
    

文末

那么对于想坚持程序员这行的真的就一点希望都没有吗?
其实不然,在互联网的大浪淘沙之下,留下的永远是最优秀的,我们考虑的不是哪个行业差哪个行业难,就逃避掉这些,无论哪个行业,都会有他的问题,但是无论哪个行业都会有站在最顶端的那群人。我们要做的就是努力提升自己,让自己站在最顶端,学历不够那就去读,知识不够那就去学。人之所以为人,不就是有解决问题的能力吗?挡住自己的由于只有自己。
Android希望=技能+面试

CodeChina开源项目地址:https://codechina.csdn.net/m0_60958482/android_p7

  • 技能
    [外链图片转存中…(img-OgtC0NjS-1631107610537)]
  • 面试技巧+面试题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值