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

移动端对大批量图片加载的优化方法(三)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…

【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;甚至…

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

目录 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通…

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

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

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.…

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 代码实…

AQS应用之BlockingQueue详解

概要 AQS全称是 AbstractQueuedSynchronizer&#xff0c;中文译为抽象队列式同步器。BlockingQueue&#xff0c;是java.util.concurrent 包提供的用于解决并发生产者 - 消费者问题的最有用的类&#xff0c;它的特性是在任意时刻只有一个线程可以进行take或者put操作&#xff0…

MySQL之导入导出远程备份

目录 一. navicat导入导出 二. mysqldump命令导入导出 导入 导出 三. load data infile命令导入导出 导入 导出 四. 远程备份 导入 导出 思维导图 一. navicat导入导出 导入&#xff1a;右键➡运行SQL文件 导出&#xff1a;选中要导出的表➡右键➡转储SQL文件➡数据和结…

C# Emgu.CV4.8.0读取rtsp流录制mp4可分段保存

【官方框架地址】 https://github.com/emgucv/emgucv 【算法介绍】 EMGU CV&#xff08;Emgu Computer Vision&#xff09;是一个开源的、基于.NET框架的计算机视觉库&#xff0c;它提供了对OpenCV&#xff08;开源计算机视觉库&#xff09;的封装。EMGU CV使得在.NET应用程序…

x-cmd pkg | vhs - 将终端的操作过程录制成视频文件的终端录制工具

目录 简介首次用户声明式录制脚本其他功能竞品和相关作品进一步阅读 简介 vhs 是一个命令行录制工具&#xff0c;用于将终端的操作过程录制成视频文件。是由 Charmbracelet 团队使用 Go 开发的&#xff0c;首个版本发布于 2022 年 10 月。开源不到一个月有接近 8k 的 star。 …

Kubernetes (八) 金丝雀发布

一. 金丝雀发布作用&#xff1a; 金丝雀发布是指在生产环境中逐步推出新版本应用程序&#xff0c;只在一小部分用户或流量中使用该版本&#xff0c;并根据反馈逐步扩…

Redis(三)持久化

文章目录 RDB&#xff08;Redis Database&#xff09;自动触发保存频率修改dump文件保存路径修改文件保存名称dump恢复 手动触发save![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a56fdff44aee4efa96c2ce3615b69dc1.png)bgsave 优劣优点缺点 检查修复dump文件会触…

手把手教你使用cubemx配置串口

重写fput函数 #include <stdio.h>#ifdef __GNUC__#define PUTCHAR_PROTOTYPE int _io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endif /* __GNUC__*//*******************************************************************brief R…

安全狗获评CCIA“2023年度先进会员单位”

1月4日&#xff0c;2023年度中国网络安全产业联盟会员大会暨理事会在北京成功举办。 作为国内云原生安全领导厂商&#xff0c;安全狗也受邀出席此次活动。 厦门服云信息科技有限公司&#xff08;品牌名&#xff1a;安全狗&#xff09;创办于2013年&#xff0c;是国内领先的云…