【flutter】高仿某东商城flutter版本之性能优化

473 阅读2分钟

1、前言

高仿某东商城flutter版本是个人学习flutter的练手项目,开源以来收到几位同学的反馈,存在性能问题。

image image

本人用的21款M1 Pro的MacBook Pro,一直使用ios模拟器开发,很流畅,收到反馈后,找了几个Android设备跑了下的确比较卡 😓 ,于是抽时间进行了优化,先看下优化后的效果,再分享下优化的点

image

可以看到优化后的UI线程Raster线程均为绿色

2、优化

2.1 使用LazyLoadIndexedStack替代IndexedStack实现首页、分类、购物车、我的4个tab页面懒加载

image
LazyLoadIndexedStack源码
import 'package:flutter/widgets.dart';

class LazyLoadIndexedStack extends StatefulWidget {
  late final Widget unloadWidget;

  final AlignmentGeometry alignment;

  final StackFit sizing;

  final TextDirection? textDirection;
  
  final int index;

  final List<Widget> children;

  LazyLoadIndexedStack({
    Key? key,
    Widget? unloadWidget,
    this.alignment = AlignmentDirectional.topStart,
    this.sizing = StackFit.loose,
    this.textDirection,
    required this.index,
    required this.children,
  }) : super(key: key) {
    this.unloadWidget = unloadWidget ?? Container();
  }

  @override
  LazyLoadIndexedStackState createState() => LazyLoadIndexedStackState();
}

class LazyLoadIndexedStackState extends State<LazyLoadIndexedStack> {
  late List<Widget> _children;
  final _stackKey = GlobalKey();

  @override
  void initState() {
    super.initState();

    _children = _initialChildren();
  }

  @override
  void didUpdateWidget(final LazyLoadIndexedStack oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (widget.children.length != oldWidget.children.length) {
      _children = _initialChildren();
    }

    _children[widget.index] = widget.children[widget.index];
  }

  @override
  Widget build(final BuildContext context) {
    return IndexedStack(
      key: _stackKey,
      index: widget.index,
      alignment: widget.alignment,
      textDirection: widget.textDirection,
      sizing: widget.sizing,
      children: _children,
    );
  }

  List<Widget> _initialChildren() {
    return widget.children.asMap().entries.map((entry) {
      final index = entry.key;
      final childWidget = entry.value;
      return index == widget.index ? childWidget : widget.unloadWidget;
    }).toList();
  }
}

2.2 使用MasonryGridView.builder替代MasonryGridView.count

image MasonryGridView.builder适用于大量数据的场景,这里有助改善性能

2.3 使用flutter_redux有大坑,不能用来记录滚动条的位置,因为滚动会一直触发build,这是导致卡顿的重要原因,感觉后面有项目会选择其他状态管理库,比如 get、provider

为什么会选择flutter_redux。一直从事前端开发,对redux比较熟练,恰巧看到了flutter_redux就用了,刚刚学习flutter,前期也不知道get、prvider等库。前端的redux只有用到这个变量才会build,这里flutter_redux明明这个widget没有用到store里的某个属性,这个属性变了,widget还刷新,这里不知道是我用的不对,还是就是不支持,有清楚的同学可以告知下

使用ValueListenableBuilder改造,频繁变更的状态剥离flutter_reudx。

inal ValueNotifier<double> _pageScrollY = ValueNotifier<double>(0);
return NotificationListener<ScrollNotification>(
  onNotification: (ScrollNotification notification) {
    int depth = notification.depth;
    double distance = notification.metrics.pixels;
    if (depth == 0) {
      _pageScrollY.value = distance;
    }
    return false;
  }
  ...
ValueListenableBuilder<double>(
  builder: (BuildContext context, double value, Widget? child) {
    return Positioned(
      top: calc2Top(value),
      child: Container(
        height: 34,
        width: getScreenWidth(context) - calcWidth(value),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(12),
          color: Colors.white,
        ),
        child: child,
      ),
    );
  },
  valueListenable: pageScrollY,
  child: Row(
    crossAxisAlignment: CrossAxisAlignment.center,
    children: <Widget>[
      SizedBox(
        width: 40,
        height: 34,
        child: UnconstrainedBox(
          child: assetImage('images/ic_search.png', 20, 20),
        ),
      ),
      Expanded(
        flex: 1,
        child: Container(
          height: 34.0,
          alignment: Alignment.centerLeft,
          child: Text(
            S.of(context).homeSearchTip,
            style: TextStyle(
              fontSize: 14,
              color: CommonStyle.placeholderColor,
            ),
          ),
        ),
      ),
      SizedBox(
        width: 40,
        height: 34,
        child: UnconstrainedBox(
          child: assetImage('images/ic_camera.png', 20, 20),
        ),
      )
    ],
  ),
)

3、结尾

感谢以上两位的反馈,优化的分享到此结束,希望大家都可以写出高性能的代码,最后再次贴出源码 github.com/GuoguoDad/j…