Volley使用介绍
安卓开发要对几个网络开源库非常熟悉:OkHttp、Volley、Retrofit。先从轻量级的网络请求库Volley学习,它的源码不到1万行,麻雀虽小五脏俱全。
1、Volley介绍
Volley是Google官方2013年发布的Android平台的网络通信库。该开源框架目前看来已经非常稳定,大部分代码提交记录定格在3年前(不是没人维护了,而是不需要再修改)。
GitHub:google/volley
1.1、特点
可以访问普通的网络数据、或者Json数据、再或者下载图片。这写都是Android开发中最常见的网络请求场景,使用Volley可以提高项目的开发效率,降低重复工作,这么好的轮子不用?
此外,Volley还可以对请求队列进行排序,取消,缓存等。
1.2、适用场景
Volley适合进行数据量不大但是通信频繁的网络操作,比如评论、点赞等场景。
但对于数据量比较大的网络操作其性能表现就比较差,不宜用Volley下载文件操作、短视频缓存。此时应该选用其它合适的网络库或者开发者用原生的HttpURLConnection实现。
2、引入Volley
在项目的build.gradle中添加下面Volley依赖,最新稳定版本是1.1.1,很久没有更新了。参考Android 开发者 > 文档 > 指南 > Volley 概览
dependencies {
...
implementation 'com.android.volley:volley:1.1.1'
}
使用Volley别忘了在AndroidManifest.xml中添加android.permission.INTERNET网络权限
<!--网络权限-->
<uses-permission android:name="android.permission.INTERNET" />
3、请求回调Listener
每个请求都需要一个结果返回监听器Listener<T>和者错误监听器ErrorListener,它们都是定义在Response<T>中的接口。在请求返回后在主线程中回调Listener<T>的onResponse(T response)方法,当请求失败出错,则回调ErrorListener的onErrorResponse(VolleyError error)方法。
/** Callback interface for delivering parsed responses. */
public interface Listener<T> {
/** Called when a response is received. */
void onResponse(T response);
}
/** Callback interface for delivering error responses. */
public interface ErrorListener {
/**
* Callback method that an error has been occurred with the provided error code and optional
* user-readable message.
*/
void onErrorResponse(VolleyError error);
}
4、请求示例
Volley将网络请求抽象为Request<T>,内部有三个实现类:StringRequest、JsonRequest、ImageRequest。用Kotlin分别简单演示一下Volley请求网络数据、Json数据、加载图片。参考Android 开发者 > 文档 > 指南 > 提出标准请求。
源码流程以后再研究。
4.1、StringRequest
先构造一个StringRequest文本请求,有两个构造函数:
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
public StringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
this(Request.Method.GET, url, listener, errorListener);
}
构造好StringRequest之后将其添加到Volley请求队列中。
private fun stringRequest() {
val url: String = "https://www.baidu.com"
val stringRequest: StringRequest = StringRequest(Request.Method.GET, url,
{
//callback in main thread
textView.text = it.toString()
Log.d(TAG, it.toString())
},
{
Log.e(TAG, it.message.toString())
})
Volley.newRequestQueue(this).add(stringRequest)
}
4.2、JsonRequest(JsonObjectRequest 和 JsonArrayRequest)
JsonRequest已经被废弃,取而代之的是两个子类JsonObjectRequest和JsonArrayRequest。分别用来解析Json对象和Json数组。
JsonArrayRequest的构造方法参数如下
public JsonArrayRequest(String url, Listener<JSONArray> listener, ErrorListener errorListener) {
super(Method.GET, url, null, listener, errorListener);
}
public JsonArrayRequest(int method, String url, JSONArray jsonRequest,
Listener<JSONArray> listener, ErrorListener errorListener) {
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener);
}
JsonObjectRequest的构造方法参数如下
public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
Listener<JSONObject> listener, ErrorListener errorListener) {
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener);
}
public JsonObjectRequest(String url, JSONObject jsonRequest,
Listener<JSONObject> listener, ErrorListener errorListener) {
this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest, listener, errorListener);
}
构造好JsonRequest之后将其添加到Volley请求队列中。
private fun jsonRequest() {
val url: String = "http://quibbler.cn:3000/search?keywords=海阔天空"
val jsonRequest: JsonObjectRequest = JsonObjectRequest(Request.Method.GET,
url,
null,
{
//JSONObject
textView.text = it.toString()
},
{
Log.d(TAG, it?.message.toString())
})
VolleyInstance.addToRequestQueue(jsonRequest)
}
4.3、ImageRequest
构造ImageRequest的参数比较多,也是合情合理,熟悉网络图片加载的开发应该对这些参数比较熟悉。关于Bitmap见Bitmap位图介绍。
/**
* @param url 图片地址
* @param listener 请求响应成功回调
* @param maxWidth 图片最大宽度
* @param maxHeight 图片最大高度
* @param scaleType ImageViews ScaleType用于计算所需的图像大小。
* @param decodeConfig 图片的颜色属性,其值是Bitmap.Config类的几个常量
* @param errorListener 请求响应失败回调
*/
public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
ImageView.ScaleType scaleType, Bitmap.Config decodeConfig, Response.ErrorListener errorListener) {
super(Request.Method.GET, url, errorListener);
...
}
构造好ImageRequest之后将其添加到Volley请求队列中加载图片,网络图片加载完成回调中可以直接设置给ImageView控件。
private fun imageRequest() {
val url: String = "http://quibbler.cn/upload/forum/10.png"
val imageRequest: ImageRequest = ImageRequest(url,
{
//Bitmap
imageView.setImageBitmap(it)
},
200, 200,
ImageView.ScaleType.FIT_CENTER,
Bitmap.Config.ALPHA_8,
{
Log.d(TAG, it?.message.toString())
})
imageRequest.setShouldCache(true).setTag(TAG)
VolleyInstance.addToRequestQueue(imageRequest)
}
5、最佳单例Volley
得益于Kotlin的语法层面支持,可以完美的实现一个Volley单例,整个应用全局可以获取RequestQueue进行请求,这样的单例是最高效的。而且应该通过全局Application Context初始化,而不是Activity的Context,获取应用全局Context方法见如何获取全局Context?。参考Android 开发者 > 文档 > 指南 > 使用单例模式。
import android.graphics.Bitmap
import android.util.LruCache
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.ImageLoader
import com.android.volley.toolbox.Volley
object VolleyInstance {
private val requestQueue: RequestQueue = Volley.newRequestQueue(MyApplication.getApplication())
private val imageLoader: ImageLoader = ImageLoader(requestQueue,
object : ImageLoader.ImageCache {
val cache = LruCache<String, Bitmap>(20)
override fun getBitmap(url: String): Bitmap {
return cache.get(url)
}
override fun putBitmap(url: String, bitmap: Bitmap) {
cache.put(url, bitmap)
}
}
)
fun <T> addToRequestQueue(request: Request<T>) {
requestQueue.add(request)
}
fun cancelRequest(tag: String?) {
requestQueue.cancelAll(tag)
}
fun getRequestQueue(): RequestQueue {
return requestQueue
}
fun getImageLoader(): ImageLoader {
return imageLoader
}
}
使用Java开发的项目单例模式详见单例的五种方式。
参考资料:
google/volley
Android 开发者 > 文档 > 指南 > Volley 概览
Android 开发者 > 文档 > 指南 > 发送简单请求
Android 开发者 > 文档 > 指南 > 设置 RequestQueue
Android 开发者 > 文档 > 指南 > 提出标准请求
Android 开发者 > 文档 > 指南 > 实现自定义请求