Flutter 图片选择器性能优化实践

20 篇文章 2 订阅

Flutter 图片选择器性能优化

##:使用Flutter实现了一个图片选择器控件,集成到Hilight里面。 自测发现在一些低端机上会有卡顿现象,需要优化下才能提测

git项目地址

ui截图

优化项目:

1. 局部刷新

最先想到的是这个,每次数据变动只刷新对应变动的UI,避免直接用 setState 全屏刷新。具体是实现是:

  • 尽可能使用const。 使用const的 对象只会实例一次
  • 把 build方法抽取出 独立控件,构造函数 尽量设置成const.
  • 使用ValueNotifier 来实现局部刷新。比对了几种状态管理的模型,觉得这个地方ValueNotifier会比较合适
//初始化包装:
  ValueNotifier<int> segmentValue = ValueNotifier(0);
//数据更改:
    segmentValue.value = value;

//触发UI刷新:
      child: ValueListenableBuilder(
        valueListenable: segmentValue,
        builder: (context, value, child) {
          return Stack(
            alignment: Alignment.topCenter,
            children: <Widget>[
              Center(
                child: _segment(),
              ),
              Positioned(
                top: 16,
                child: btnClose(),
                right: 16,
              )
            ],
          );
        },
      ),

2. 分页优化

  • 修改分页触发时机,提前点加载。
scroll.metrics.pixels / scroll.metrics.maxScrollExtent > 0.7
  • 只接收ScrollEndNotification事件,来实现 滑动停止时加载
 return NotificationListener<ScrollEndNotification>(
      onNotification: (ScrollEndNotification scroll) {
        _handleScrollEvent(scroll);
        return true;
      },
  • 避免 notification 通知重复触发,引入loading来判断,如果正在请求分页,不重复请求
  _handleScrollEvent(ScrollNotification scroll) {
    if (scroll.metrics.pixels / scroll.metrics.maxScrollExtent > 0.7) {
      if (!isEnd && !loading) {
        _fetchNewMedia(pathEntity);
      }
    }
  }

    _fetchNewMedia(AssetPathEntity pathEntity) async {
    loading = true;
    List<AssetEntity> media =
        await pathEntity.getAssetListPaged(currentPage, 60);

    if (media.isEmpty) {
      isEnd = true;
      return;
    } else {
      setState(() {
        _mediaList.addAll(media);
        currentPage++;
        loading = false;
      });
    }
  }

完整的例子可以参考: git地址

内存优化

  • 由于messageChannel会被频繁调用,因此native那边需要设置一个线程池来缓冲请求。
  • flutter 实现LRU 缓存功能,使用内存缓存已经获取的图片,加快图片显示速度
  • 根据产品UI,确定要加载的图片宽高,来加载图片。
//默认GridView小图的宽: 
MediaQuery.of(context).size.width / (3 * 2);

//预览图的宽: 
MediaQuery.of(context).size.width 

页面初始化优化

  • 尽量在 widget的 initState里面 请求数据,避免build里面重复请求
  • 把FutureBuild的初始化放在 initState里面,设置为成员变量,减少重复调用
  Future<AssetPathEntity> recentFolder;

  @override
  void initState() {
    super.initState();
    recentFolder = getRecentFolder();
  }

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre非常不错的图片选择器,功能完善,动画超赞Louvre
acility); } void Playground::removeFacility(int index) { facilities_.erase(facilities_.begin() + index); } double Playground::getFacilityIncomeOnDate(int index, const std::string &date) const { return facilities_[index].getFlutter 中可以使用 image_picker 插件来实现图片选择器功能,同时可以根据自己的需求对图库样IncomeOnDate(date); } double Playground::getTotalIncomeOnDate(const std::string &date) const { double income = 式进行修改。 下面是一个基于 image_picker 插件的图片选择器示例,其中使用自定义的图库样0; for (auto facility : facilities_) { income += facility.getIncomeOnDate(date); } return income; } 式: ```dart import 'dart:io'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; void maindouble Playground::getTotalIncome() const { double income = 0; for (auto facility : facilities_) { income +=() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: facility.getTotalIncome(); } return income; } std::vector<PlayFacility> Playground::getSortedFacilitiesByName() const 'Image Picker Demo', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _My { std::vector<PlayFacility> facilities = facilities_; std::sort(facilities.begin(), facilities.end(), PlayFacHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { File _image; Futureility::sortByName); return facilities; } std::vector<PlayFacility> Playground::getSortedFacilitiesByIncome() const getImage() async { var image = await ImagePicker.pickImage(source: ImageSource.gallery); setState(() { _image = image; { std::vector<PlayFacility> facilities = facilities_; std::sort(facilities.begin(), facilities.end(), PlayFac }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ility::sortByIncome); return facilities; } void Playground::saveToFile(const std::string &filename) const { FileIO::Image Picker Demo'), ), body: Center( child: _image == null ? Text('No image selected.') :writeToFile(filename, facilities_); } ``` 主函数(main.cpp): ```c++ #include <iostream> #include "Playground.h" int main() { Playground playground("playground.txt"); int option = 0; do { std::cout << " Image.file(_image), ), floatingActionButton: FloatingActionButton( onPressed: getImage, tooltip: 'Pick Image', child:1. Add a new facility" << std::endl; std::cout << "2. Remove a facility" << std::endl; Icon(Icons.add_a_photo), ), ); } } ``` 在这个示例中,我们使用 ImagePicker.pickImage() std::cout << "3. Get income of a facility on a date" << std::endl; std::cout << "4 方法来选择图片,通过传递 ImageSource.gallery 参数来打开图库。你可以根据自己的需求来修改图库的样式,比如使用自定义的按钮、图标、字体等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值