移动端对大批量图片加载的优化方法(三)

移动端对大批量图片加载的优化方法(三)Flutter

本篇主要从Flutter开发中可以使用到的对大批量图片加载的优化方法进行整理。优化

1.合适的图片格式

详情请参考移动端对大批量图片加载的优化方法(一)。

2.缓存机制

在Flutter中,处理大批量图片加载的缓存机制主要是依赖于第三方库和Flutter自身的架构;

a.缓存库

Glide和CacheableImage等可以自动处理图片的缓存和加载,使你能够更专注于应用的其他部分。

Future<void> _cacheImage() async {  // 指定要缓存的图片URL或路径  String imageUrl = 'https://example.com/image.jpg';  // 使用Glide加载图片并缓存到磁盘中  await Glide.with(context)  .load(imageUrl)  .into(Image.network(imageUrl)); // 将图片设置到Image widget中  } 
Future<void> _cacheImage() async {  // 指定要缓存的图片URL或路径  String imageUrl = 'https://example.com/image.jpg';  // 使用CacheableImage加载图片并缓存到磁盘中  await CacheableImage.network(imageUrl).cache(); // 缓存图片到磁盘中  }  
b.自定义缓存策略

不能使用第三方库,或者需要更精细的控制,可以创建一个自定义的缓存策略;
可以使用一个持久化的存储(如SQLite或SharedPreferences)来存储已经加载过的图片,并在需要时从缓存中检索它们;

Future<void> _cacheImage() async {  // 指定要缓存的图片URL或路径  String imageUrl = 'https://example.com/image.jpg';  // 加载图片并将其转换为字节数组  final response = await http.get(imageUrl);  final imageBytes = response.bodyBytes;  // 将字节数组写入SharedPreferences中作为二进制数据  SharedPreferences prefs = await SharedPreferences.getInstance();  prefs.setInt('image_length', imageBytes.length);  prefs.setInt('image_data', imageBytes.hashCode); // 使用哈希值作为键来存储二进制数据  }  

注意:可以但不推荐,SharedPreferences一般存储小量数据。

c.Flutter的缓存机制

Flutter本身提供了一些机制来管理资源,包括图片;
可以使用Flutter的AssetBundle API来控制图片的加载和缓存;
这个API允许从资源文件中加载图片,并可以在应用重启后保持这些图片的持久化。

Future<Image> loadImageFromAssetBundle() async {  final AssetBundle bundle = await AssetBundle.fromBundle(context);  final Uint8List imageBytes = await bundle.loadBytes('assets/image.jpg');  final Image image = Image.memory(imageBytes);  return image;  }  

3.异步加载

处理大量图片的异步加载是一个重要的任务,因为图片加载可能会阻塞UI线程,导致应用界面的卡顿;

a.FutureBuilder

FutureBuilder是一个构建器,用于处理Future。

FutureBuilder<List<dynamic>>(  future: fetchImages(), // 假设fetchImages是一个返回Future<List<dynamic>>的函数  builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {  if (snapshot.connectionState == ConnectionState.waiting) {  return CircularProgressIndicator(); // 加载中的UI  } else if (snapshot.hasError) {  return Text('Error: ${snapshot.error}');  } else {  return ListView(children: snapshot.data.map((image) => Image.network(image)).toList());  }  },  
);
b.异步函数

使用async和await关键字来编写异步函数,并在函数内部执行图片加载操作。

Future<void> loadImages() async {  List<dynamic> images = await fetchImages(); // 假设fetchImages是一个返回Future<List<dynamic>>的函数  // 处理加载完成的图片列表  
}
c.comet_engine

使用Comet引擎库来异步加载图片。

Future<Image> loadImage() async {  String imageUrl = 'https://example.com/image.jpg'; // 替换为你要加载的图片URL  CometTask task = _engine.getTask(CometRequestType.networkImage, imageUrl); // 创建网络图片请求任务  await task.waitForFinish(); // 等待任务完成并获取图片数据  return Image.memory(task.result.bodyBytes, imageUrl); // 创建Image对象并返回  }  

4.懒加载

对于列表或滚动视图中的图片,可以使用懒加载技术,只在需要显示时才加载图片。

ListView(  itemCount: imageUrls.length,  itemBuilder: (context, index) {  return Visibility(  visible: imageLoaded[index], // 假设imageLoaded是一个bool类型的列表,用于记录图片是否已加载完成  child: Image.network(imageUrls[index]), // 加载图片的URL或路径  onLoaded: () { // 图片加载完成后的回调函数  setState(() { // 更新UI状态时需要调用setState函数,确保UI的重新构建和更新  imageLoaded[index] = true; // 将对应图片的状态设置为已加载完成  });  },  );  }

5.控制图片大小

根据需要显示的大小加载图片,避免加载过大的图片。

Image(  image: AssetImage('assets/images/my_image.jpg'), // 加载图片资源  fit: BoxFit.cover, // 控制图片大小的方式,这里使用cover方式,即保持图片的纵横比并填充整个约束器  
)

6.优化内存管理

a.清理不再需要的图片

当图片不再需要时,及时清理它们以释放内存;
可以在图片不再可见时销毁对应的组件或使用Flutter的垃圾回收机制来清理不再使用的对象;

Image image = Image.network('https://example.com/image.jpg');  
// ... 显示图片 ...  
// 当图片不再需要时  
image.dispose();
// 清除所有缓存的图片  
ImageCache.clear();

或者使用Offstage或Visibility来控制图片的显示,当图片不再需要显示时,可以将其移到Offstage或隐藏起来;
这不会立即释放资源,但可以避免在不需要时显示不必要的图片;
当用户导航离开某个页面时,可能需要清理该页面加载的图片资源。

b.使用低质量预览图

在加载高质量图片之前,可以先显示一个低质量的预览图;
可以快速看到图片的大致内容,同时避免了长时间的等待和内存占用;
以下是使用image_utils生成预览图的示例:

// 加载原始图片  Uint8List imageBytes = ...; // 获取图片的字节数据  Image originalImage = Image.fromBytes(imageBytes);  // 降低图像质量  int quality = 50; // 设置质量等级,范围为0-100  Image lowQualityImage = originalImage.scale(quality);  
c.限制同时加载的图片数量

限制同时加载的图片数量,例如使用队列或优先级队列来管理图片的加载顺序。

class ImageLoader {  Queue<Future<void>> _queue = Queue<Future<void>>();  int _maxSimultaneousLoads = 3; // 设置并发加载的最大数量  Future<void> loadImage(String url) async {  if (_queue.length < _maxSimultaneousLoads) {  _queue.add(loadImageInternal(url));  } else {  // 等待当前队列中的图片加载完成后再加载新图片  await Future.wait(_queue);  _queue.add(loadImageInternal(url));  }  }  Future<void> loadImageInternal(String url) async {  // 加载图片的逻辑...  // 假设这里使用Image.network加载图片  await Image.network(url);  }  
}

7.预加载

在用户请求图片之前预先加载它们,从而提高图片加载速度和响应性。

class PreloadedImage extends StatefulWidget {  final String imageUrl;  final int fetchDelay; // 延迟时间(毫秒)  final bool useCache; // 是否使用缓存  PreloadedImage({required this.imageUrl, this.fetchDelay = 500, this.useCache = true});  @override  _PreloadedImageState createState() => _PreloadedImageState();  
}  class _PreloadedImageState extends State<PreloadedImage> {  late Future<Uint8List> _futureImage;  late Image _imageWidget;  @override  void initState() {  super.initState();  _futureImage = Future<Uint8List>.delayed(Duration(milliseconds: widget.fetchDelay), () async {  return await http.get(widget.imageUrl).then((response) => response.bodyBytes);  });  }  @override  Widget build(BuildContext context) {  if (_futureImage != null && !_futureImage.done) {  return CircularProgressIndicator(); // 显示加载指示器  } else if (_futureImage == null) {  return Text('Image not loaded'); // 初始状态  } else {  final Uint8List imageBytes = _futureImage.result;  final ImageProvider imageProvider = Image.memory(imageBytes);  _imageWidget = Image(image: imageProvider,); // 使用图片数据构建图像Widget  return _imageWidget; // 显示图像Widget  }  }  
}

8.合适的View类型

ListView:当有大量可滚动的内容,并且每个项都是一个图片时,使用ListView是最佳选择;
它可以有效地重用子项,减少内存占用,并且可以水平或垂直滚动。
GridView:如果需要显示一个网格布局的图片,并且图片数量是动态的,可以使用GridView;
每个格子中可以放置一个小图片或缩略图。
Stack & Positioned:当需要动态创建大量浮动的图片层时,可以使用Stack和Positioned;
每个Positioned都可以放置一个图片,并且可以设置不同的位置和大小。
Image Widgets:直接使用Image小部件来显示单张大图或一组小图;
对于单张大图,可以使用Image.network或Image.asset来加载;
对于一组小图,可以使用ListView.builder结合Image.network或Image.asset来构建。
Cached Image:使用第三方库如cached_network_image来缓存网络图片,提高加载速度和性能;
这个库提供了预加载和缓存机制,非常适合加载大量图片。
FittedBox or Container with Fit.xxx:当需要精确控制图片的尺寸或者进行一些自定义布局时,可以使用FittedBox或Container的fit属性;
这样可以确保图片不会超出预期尺寸,从而优化内存使用。

9.优化网络请求

详情请参考移动端对大批量图片加载的优化方法(二)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/608636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈对Promise的理解。

一、Promise定义 JS中用于处理异步操作的编程模式。一个Promise是一个代理&#xff0c;它代表一个创建Promise时不一定已知的值。它允许我们将处理的程序与异步操作的最终成功值或失败值原因想关联起来。这使得异步方法可以像同步方法一样返回值&#xff1a;异步方法不会立即返…

uniapp最简单的底部兼容安全区域显示

效果图&#xff1a; 1.html写上动态padding-bottom <view class"button-wrap" :style"padding-bottom:bottomPaddingrpx"><view class"com-btn cencel-btn">取消</view><view class"com-btn confirm-btn " cl…

神经网络中的梯度爆炸

梯度爆炸是深度学习中的一种常见问题&#xff0c;指的是在反向传播过程中&#xff0c;某些梯度的值变得非常大&#xff0c;导致数值溢出或趋近于无穷大。梯度爆炸通常会导致训练不稳定&#xff0c;模型无法收敛&#xff0c;或者产生不可靠的结果。 梯度爆炸可能发生在深度神经…

【PostgreSQL创建索引的锁分析和使用注意】

1.1 创建普通B-tree索引的整体流程 如下是梳理的创建普通B-tree索引的大概流程&#xff0c;可供参考。 1.校验新索引的Catalog元数据|语法解析 ---将创建索引的sql解析成IndexStmt结构&#xff5c;校验B-Tree的handler -----校验内核是否支持该类型的索引,在pg_am中查找&q…

java 体育明星管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web 体育明星管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysq…

Clojure 实战(4):编写 Hadoop MapReduce 脚本

Hadoop简介 众所周知&#xff0c;我们已经进入了大数据时代&#xff0c;每天都有PB级的数据需要处理、分析&#xff0c;从中提取出有用的信息。Hadoop就是这一时代背景下的产物。它是Apache基金会下的开源项目&#xff0c;受Google两篇论文的启发&#xff0c;采用分布式的文件…

Spark Core--加强

RDD的持久化 RDD缓存 当RDD被重复使用&#xff0c;或者计算该RDD比较容易出错&#xff0c;而且需要消耗比较多的资源和时间的时候&#xff0c;我们就可以将该RDD缓存起来。 主要作用: 提升Spark程序的计算效率 注意事项: RDD的缓存可以存储在内存或者是磁盘上&#xff0c;甚至…

小程序开发之uniapp项目框架搭建

出于对技术的实践&#xff0c;以及博主最近刚刚拥有了一台自己的云服务器&#xff0c;本着闲着也是闲着的态度&#xff0c;准备着手开发一款快递下单、查询快艇实时状态的多端小程序&#xff0c;又不想在各个小程序平台重复开发&#xff0c;因此选择了uinapp 。 博主先讲诉一下…

【数据结构】二叉树链式结构详解

目录 1.前言2.快速创建一颗二叉树3.二叉树的遍历3.1前序遍历3.2中序遍历3.3后序遍历3.4层序遍历 4.二叉树节点个数与高度4.1二叉树节点个数4.2二叉树叶子节点个数4.3二叉树高度4.4二叉树第k层节点个数4.5二叉树查找值为x的节点 5.二叉树的基础oj题练习6.二叉树的创建和销毁6.1通…

贪心算法的“左最优“与“右最优“

1 答疑 1.1 什么是贪心算法的"左最优"与"右最优" "左最优"和"右最优"是贪心算法中的两种策略&#xff1a; 左最优 (Leftmost Greedy): 在每一步选择中&#xff0c;总是选择最左边&#xff08;最早出现的&#xff09;可行的选项。 右…

JVM,JRE,JDK的区别和联系简洁版

先看图 利用JDK&#xff08;调用JAVA API&#xff09;开发JAVA程序后&#xff0c;通过JDK中的编译程序&#xff08;javac&#xff09;将我们的文本java文件编译成JAVA字节码&#xff0c;在JRE上运行这些JAVA字节码&#xff0c;JVM解析这些字节码&#xff0c;映射到CPU指令集或…

洛谷——P1069 [NOIP2009 普及组] 细胞分裂(分解质因数,唯一分解定理)

文章目录 一、题目[NOIP2009 普及组] 细胞分裂题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示 二、题解1.基本思路&#xff1a;2.代码&#xff1a; 一、题目 [NOIP2009 普及组] 细胞分裂 题目描述 Hanks 博士是 BT&#xff08;…

粒子群算法优化支持向量SVM的供热量预测,粒子群优化支持向量机SVM回归分析

目录 背影 支持向量机SVM的详细原理 SVM的定义 SVM理论 粒子群算法原理 SVM应用实例,粒子群算法优化支持向量SVM的供热量预测,粒子群优化支持向量机SVM回归分析 代码 结果分析 展望 完整代码:粒子群算法优化支持向量SVM的供热量预测,粒子群优化支持向量机SVM回归分析_lssv…

Spring学习 基于注解的AOP配置

5.1.创建工程 5.1.1.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.ap…

springCould中的Config-从小白开始【10 】

目录 &#x1f32d;1.spring cloud Config是什么&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️ &#x1f953;2.能干什么&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️ &am…

SSH远程访问出现Permission denied(password)解决方法

首先&#xff0c;这个不是密码输错了的问题&#xff1b; 1、在主机先ping一下服务器 ping XXX.XXX.XX.XXX (服务器ip地址) 如果pin成功了&#xff0c;说明可以进行连接 查看服务器的ip ifconfig2、主机连接服务器 &#xff08;服务器的ip&#xff09; ssh testXXX.XXX.XX.…

mysql 删除查询语句所选出的数据 SQL查询,用于找出outbox表中memo1字段重复且dt字段不是最新日期的记录

编写一个SQL查询&#xff0c;用于找出outbox表中memo1字段重复且dt字段不是最新日期的记录 批量打印包装箱时&#xff0c;提示有重复N条的处理方法&#xff1a; –先备份数据库&#xff0c;删除不可逆。查出来&#xff0c;如果就是重复的N条&#xff0c;全选右键 删除 SELECT …

LeetCode-数组-双指针-中等难度

文章目录 双指针1. 删除有序数组中的重复项&#xff08;入门&#xff09;1.1 题目描述1.2 解题思路1.3 代码实现 2. 删除有序数组中的重复项 II&#xff08;简单&#xff09;2.1 题目描述2.2 解题思路2.3 代码实现 3. 移动零&#xff08;简单&#xff09;3.1 题目描述3.2 代码实…

Hive的时间处理函数from_unixtime和unix_timestamp

一、概述 hive时间处理函数from_unixtime和unix_timestamp的实现以及实例&#xff0c;从而方便后续的时间处理。 二、具体功能实现 1.unix_timestamp(date[, pattern])&#xff1a; 默认的时间格式是yyyy-MM-dd HH:mm:ss&#xff0c;如果日期不是这种格式无法识别&#xff…

【技术选型】clickhouse vs starRocks

比对结论 如果只能单机部署的话&#xff0c;clickhouse基本无敌。 如果集群化&#xff0c;starRocks可以替换clickhouse&#xff0c;但支持的函数会相对少一些&#xff08;clickhouse有不少自定义函数&#xff09; 信息比对 功能clickhousestarRocksjoin大表关联容易OOM对jo…