为什么说Volley适合数据量小,通信频繁的网络操作

2024-09-01 11:32

本文主要是介绍为什么说Volley适合数据量小,通信频繁的网络操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

网络编程对于客户端来说是一块及其重要的地方,使用高效的网络请求框架将为你的系统产生很大的影响。而Volley作为谷歌的一个开源项目,炙手可热。有很多中小型公司的安卓移动客户端的网络程序都是基于volley的。
Volley的优点很多,光可扩展性这一条优点就值得我们称赞。但是我想针对的是在 Google I/O 2013 大会上发布Volley的时候的一句话:a burst or emission of many things or a large amount at once(爆炸性的事件在很短的时间内发生),意思就是:Volley特别适合数据量小,通信量大的客户端。同为网络请求框架,为什么Volley会有这样的特点?接下来,我就用我的理解来解释一下。
ByteArrayPool
ByteArrayPool产生背景

根据类名,知道这是一个字节数组缓存池。没错,就是用来缓存 网络请求获得的数据。
当网络请求得到返回数据以后,我们需要在内存开辟出一块区域来存放我们得到的网络数据,不论是json还是图片,都会存在于内存的某一块区域,然后拿到UI显示,然而客户端请求是相当频繁的操作,想一下我们平时使用知乎等一些客户端,几乎每一个操作都要进行网络请求(虽然知乎大部分是WebView)。那么问题来了:这么频繁的数据请求,获得数据以后我们先要在堆内存开辟存储空间,然后显示,等到时机成熟,GC回收这块区域,如此往复,那么GC的负担就相当的重,然而Android客户端处理能力有限,频繁GC对客户端的性能有直接影响。我们能不能减少GC和内存的分配呢?我想这个问题就是这个类的产生背景。
实现原理(怎么实现缓存从而减少GC)

在ByteArrayPool中维护了两个List集合。
属性名 作用 类型
mBuffersByLastUse 按照最近使用对byte[]排序 LinkedList
mBuffersBySize 按照byte[]大小对byte[]排序 ArrayList

通过上述两个属性的作用可以分析出它们是ByteArrayPool类对byte[]的管理。
从缓冲区取空间

当请求数据返回以后,我们不是急于在内存开辟空间,而是从ByteArrayPool中取出一块已经分配的内存区域。此时会调用ByteArrayPool的getBuf(int)方法,来得到一块参数大小的区域,源码如下:

 public synchronized byte[] getBuf(int len) {for (int i = 0; i < mBuffersBySize.size(); i++) {byte[] buf = mBuffersBySize.get(i);if (buf.length >= len) {mCurrentSize -= buf.length;mBuffersBySize.remove(i);mBuffersByLastUse.remove(buf);return buf;}}return new byte[len];}

方法的第2行代码,遍历mBuffersBySize,找到最适合len大小的byte[]。第6 ~8行更新缓存池中数据的大小,并从两个数组中去除分配出去的byte[]。如果在缓存池中没有要求的byte[],此时会从内存分配一跨区域返回。
此方法主要的功能: 不必每次存数据都要进行内存分配,而是先查找缓冲池中有无适合的内存区域,如果有,直接拿来用,从而减少内存分配的次数。
其实这个方法有改进空间:由于在类中有一个mSizeLimit属性,表示此缓冲区的最大值。我们可以在方法体的第一行判断 len与mSizeLimit的大小,如否 len>mSizeLimit,直接进入到最后一句运行,否则,循环。修改后的方法如下:

public synchronized byte[] getBuf(int len) {//有的条件不需循环if(len<=mSizeLimit){for (int i = 0; i < mBuffersBySize.size(); i++) {byte[] buf = mBuffersBySize.get(i);if (buf.length >= len) {mCurrentSize -= buf.length;mBuffersBySize.remove(i);mBuffersByLastUse.remove(buf);return buf;}}}return new byte[len];}

将空间返回给缓存池

如果只是拿数据,缓存区的只会越来越小,我们还需要向缓冲区中加入存储空间。这个时候涉及到一个方法:returnBuf(byte[])。

 public synchronized void returnBuf(byte[] buf) {if (buf == null || buf.length > mSizeLimit) {return;}mBuffersByLastUse.add(buf);int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);if (pos < 0) {pos = -pos - 1;}mBuffersBySize.add(pos, buf);mCurrentSize += buf.length;trim();}

方法首先检查 要插入的数据大小有没有超出边界,如果没有,利用二分法找到插入位置,将数据插入到上述的两个集合,完成排序。然后更新缓冲池的大小,以方便从缓冲区中取存储空间。
结语

ByteArrayPool利用getBuf和returnBuf以及mBuffersByLastUse和mBuffersBySize完成字节数组的缓存。当需要使内存区域的时候,先从已经分配的区域中获得以减少内存分配次数。当空间用完以后,在将数据返回给此缓冲区。这样,就会减少内存区域堆内存的波动和减少GC的回收,让CPU把更多的性能留给页面的渲染,提高性能。通过这个类发现,谷歌对技术的细节十分考究。

这篇关于为什么说Volley适合数据量小,通信频繁的网络操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1126809

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

Python利用自带模块实现屏幕像素高效操作

《Python利用自带模块实现屏幕像素高效操作》这篇文章主要为大家详细介绍了Python如何利用自带模块实现屏幕像素高效操作,文中的示例代码讲解详,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、获取屏幕放缩比例2、获取屏幕指定坐标处像素颜色3、一个简单的使用案例4、总结1、获取屏幕放缩比例from

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

Python中操作Redis的常用方法小结

《Python中操作Redis的常用方法小结》这篇文章主要为大家详细介绍了Python中操作Redis的常用方法,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解一下... 目录安装Redis开启、关闭Redisredis数据结构redis-cli操作安装redis-py数据库连接和释放增