Volley 是由Google开发的Android网络库,用于高效执行HTTP请求和加载图片。该库自动管理线程池、缓存响应并对请求进行优先级排序。根据 Google, 2025 的数据,Volley 仍然是需要快速启动而无需配置复杂依赖的项目的热门选择。
要点
Volley 是用于Android应用程序网络通信的库,由Google在I/O 2013大会上推出。Volley这个名字意为“齐射”——该库旨在执行多个并行快速请求,这在面向UI的应用程序中很常见,界面的响应速度至关重要。
Volley是作为HttpURLConnection和AsyncTask问题的解决方案而创建的:手动线程管理、缺乏缓存、请求优先级排序困难以及代码冗长。Google将Volley定位为用于“发射后不管”类型操作的库——结果立即显示在界面中的小型请求。
Volley的架构包括三个主要组件:RequestQueue(队列管理器)、CacheDispatcher(用于缓存响应的线程)和NetworkDispatcher(网络线程)。这种架构自动分配请求:首先检查缓存,只有在缓存不存在时才执行网络请求。这可将重复数据的延迟降低50–80%。
RequestQueue 是Volley的核心类。Request<T>对象被添加到其中,队列自动将它们分配到两种类型的线程:CacheDispatcher(一个线程,处理可能缓存的请求)和NetworkDispatcher(多个线程,执行实际的HTTP请求)。默认情况下,Volley会创建4个网络线程。
添加请求时,RequestQueue会检查是否可以由缓存提供服务。如果缓存包含最新响应,CacheDispatcher立即返回它,无需网络请求。如果缓存过期或不存在,请求将转发到NetworkDispatcher。请求优先级(low、normal、high、immediate)决定了队列中的处理顺序——高优先级请求在正常请求之前处理。
请求执行后,结果通过Handler传递到主线程(UI线程)。Volley自动将onResponse()和onErrorResponse()回调切换到主线程,因此您可以直接在回调中更新界面,无需额外的切换。这简化了代码并消除了与线程相关的一整类错误。
Volley的另一个特点是自动请求去重。如果两个相同的GET请求使用相同的参数添加到队列中的同一URL,Volley只执行其中一个并将相同的响应返回给两个回调。这对于多个组件独立请求相同数据的屏幕特别有用——例如,标题和设置片段同时需要的用户配置文件。
每个请求都经过一系列步骤:创建Request、添加到RequestQueue、检查缓存(CacheDispatcher)、执行HTTP请求(NetworkDispatcher)、通过Response.Listener解析响应、将结果传递到UI线程。取消请求时(cancel),RequestQueue将其从队列中移除并阻止回调调用。
Volley还支持RetryPolicy,它决定了失败时的重试次数。DefaultRetryPolicy默认进行1次重试,超时时间为2.5秒。对于不稳定的连接,可以将重试次数增加到3次,超时时间增加到10秒。自定义RetryPolicy通过RetryPolicy接口实现,包含getCurrentTimeout、getCurrentRetryCount和retry方法。
Volley为常见数据格式提供了现成的请求类型。每种类型都实现了抽象类Request<T>并定义了响应的解析方式。对于自定义格式,您可以通过重写parseNetworkResponse方法来创建自己的类型。
| 请求类型 | 返回类型 | 用途 |
|---|---|---|
| StringRequest | String | 获取原始文本响应 |
| JsonObjectRequest | JSONObject | 解析JSON对象 |
| JsonArrayRequest | JSONArray | 解析JSON数组 |
| ImageRequest | Bitmap | 加载和解码图片 |
| ClearCacheRequest | — | 清除Volley缓存 |
为了与Gson或Kotlinx Serialization配合使用,您可以创建自定义的Request<T>,在parseNetworkResponse中使用选定的解析器。这允许直接获取类型化对象,绕过手动JSONObject解析。这种方法对于已经使用Gson或Moshi进行序列化的项目特别有用。
对于发送数据,Volley支持三种请求体类型:JSONObject(通过使用POST方法的JsonObjectRequest)、Form-encoded(通过构造函数中的HashMap<String, String>)和Multipart(通过自定义MultipartRequest)。Multipart请求对于上传图片和文件很有用,但需要手动实现,因为Volley不像OkHttp或Dio那样内置支持multipart/form-data。
Volley的局限性在处理大响应时变得明显。Volley在将响应传递给回调之前将整个响应加载到内存中,这可能导致超过10–20 MB的JSON文件出现OutOfMemoryError。Volley不适合加载大文件——请使用DownloadManager或带有流式ResponseBody的OkHttp。Volley也不支持断点续传(Range header)并且不能与实时流协议(如Server-Sent Events或WebSocket)一起工作。
让我们来看一个基本示例——用于从服务器获取数据的StringRequest。首先通过Volley.newRequestQueue(context)创建RequestQueue。然后构建带有URL和成功/错误回调的请求。
val queue = Volley.newRequestQueue(context)
val request = StringRequest(
Request.Method.GET,
"https://api.github.com/users/octocat",
{ response ->
println("响应: $response")
},
{ error ->
println("错误: ${error.message}")
}
)
queue.add(request)
对于JSON请求,使用JsonObjectRequest,它会自动将响应解析为JSONObject。Volley支持GET和POST请求。对于POST,请求体中传递一个JSONObject。
val jsonBody = JSONObject()
jsonBody.put("name", "New Repo")
jsonBody.put("description", "Created via Volley")
val request = JsonObjectRequest(
Request.Method.POST,
"https://api.github.com/user/repos",
jsonBody,
{ response ->
println("已创建: ${response.getString("id")}")
},
{ println("错误: $it") }
)
queue.add(request)
取消请求使用cancel()方法或基于标签的组取消。取消时,Volley不会调用onResponse或onErrorResponse,从而防止离开屏幕后更新界面。这对于防止Activity和Fragment中的内存泄漏很重要。
request.tag = "profile_request"
queue.add(request)
// 离开屏幕时取消
queue.cancelAll("profile_request")
ImageLoader 是RequestQueue上的包装类,针对加载图片进行了优化。它支持内存缓存(LruCache)并在RecyclerView列表中重复使用ImageView时自动取消请求。ImageLoader还会将图片缩放到View的大小以节省内存。
NetworkImageView 是与ImageLoader集成的自定义View,自动管理加载:在加载时设置占位符,在失败时替换为错误,并在View离开屏幕时取消请求。DefaultImageUrlLoader通过URL加载图片并将其保存在LruCache中以供快速重新显示。
使用ImageLoader只需通过ImageLoader(queue, ImageCache)创建一个实例,其中ImageCache是包含LruCache的ImageCache接口的实现。XML中的NetworkImageView通过setImageUrl()方法连接到ImageLoader,整个加载过程完全自动进行,无需额外的代码来处理占位符和错误。
在每个Activity中创建RequestQueue 是一个常见错误,会导致线程重复和缓存混乱。建议在Application中或通过单例类只创建一次RequestQueue。否则,每个屏幕都将有自己的线程池,并且缓存将单独存储在每个队列中。
屏幕旋转时忽略取消请求。配置更改时,Activity会重新创建,旧Activity的回调保留在内存中。这会导致内存泄漏并尝试更新已销毁的View。始终在onStop()中通过cancelAll()使用特定于Activity的标签取消请求。
Volley不支持HTTP/2和协程——这不是使用错误,而是架构限制。Volley创建于2013年,不支持现代协议和Kotlin协程。对于新项目,Google建议使用Retrofit + OkHttp。Volley仅适用于支持遗留项目或具有最低网络要求的简单应用程序。
常见问题
Volley 对新项目来说已经过时了——Google自2017年以来就没有更新过这个库。对于现代应用程序,请使用Retrofit + OkHttp或Ktor Client。Volley仅适用于支持现有遗留代码或具有最低网络任务的简单教育项目。
缺乏对现代技术的支持:HTTP/2、Kotlin协程、跨平台和类型化序列化。Volley使用不带类型的JSONObject和JSONArray,当JSON结构与预期不符时会导致运行时错误。
通过ImageLoader和NetworkImageView。ImageLoader使用LruCache在内存中缓存图片,并在View被重复使用时自动取消请求。NetworkImageView在加载时显示占位符,并将其替换为准备好的图片或错误指示器。
技术上可以——通过围绕Volley回调的suspendCoroutine { }包装器。但这并没有优势,因为Volley不支持通过取消协程来取消,也不直接与Dispatchers.IO一起工作。最好使用具有原生协程支持的Ktor Client。
超时通过RetryPolicy设置。默认情况下,DefaultRetryPolicy使用2.5秒超时和1次重试。更改参数:request.retryPolicy = DefaultRetryPolicy(10000, 1, 1.0f) — 10秒超时,1次重试。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。