一、Volley简介
- 直接用HttpURLConnection和HttpClient进行网络请求比较复杂,不进行封装的话,会有很多重复代码
- 2013年Google I/O大会上推出了一个新的网络通信框架——Volley,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕
二、Volley的使用场景
三、导入Volley
- 从中心库加载---只能选择镜像(mcxiaoke等)
- github下载library源码—也是只有镜像的源码(比如:https://github.com/mcxiaoke/android-volley)
- google官方下载library源码:https://android.googlesource.com/platform/frameworks/volley
- 导入jar包
四、
使用Volley
- 三种基本网络请求的实现
第一步:新建请求队列:
RequestQueue mQueue = Volley.newRequestQueue(context); //一个工程用一个请求队列即可
第二步:新建request
第三步:把request加入请求队列
- StringRequest
Get请求:
mRequestQueue
= Volley.
newRequestQueue
(
this
)
;
public void stringGetRequest() {
//新建一个字符串网络请求
//第一个参数:url--请求的网址
//第二个参数:响应监听
//第三个参数:错误监听
StringRequest request = new StringRequest("https://www.baidu.com/",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("qfstringRequest",response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
//把请求加入队列
requestQueue.add(request);
}
mRequestQueue
.add(request)
;
Post请求:
接口:http://a1.greentree.cn:8029/Api/index.php/search/searchHotel
StringRequest postStringRequest =
new
StringRequest(
Request.Method.POST,
"http://a1.greentree.cn:8029/Api/index.php/search/searchHotel",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("VolleyLesson",response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("VolleyLesson",error.getMessage());
}
}
){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> mapParam = new HashMap<String,String>();
// 设置参数
// pagesize 每页多少行
mapParam.put("pagesize", "20");
// pageindex 页码
mapParam.put("pageindex", "2");
return mapParam;
}
};
mRequestQueue.add(postStringRequest);
取消重复请求:
public void postStringWithCancel(View view) {
mRequestQueue.cancelAll("test");
StringRequest postStringRequest = new StringRequest(
Request.Method.POST,
"http://a1.greentree.cn:8029/Api/index.php/search/searchHotel",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("VolleyLesson",response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("VolleyLesson",error.getMessage());
}
}
){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> mapParam = new HashMap<String,String>();
// 设置参数
// pagesize 每页多少行
mapParam.put("pagesize", "20");
// pageindex 页码
mapParam.put("pageindex", "2");
return mapParam;
}
};
postStringRequest.setTag("test");
mRequestQueue.add(postStringRequest);
}
2.JsonRequest
JsonRequest
是一个抽象类,因此我们无法直接创建它的实例,那么只能从它的子类入手了。
JsonRequest
有两个直接的子类,
JsonObjectRequest
和
JsonArrayRequest
JsonRequest jsonRequest = new JsonObjectRequest(Request.Method.POST,
"http://a1.greentree.cn:8029/Api/index.php/search/searchHotel",
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d("volleylesson",response.toString());
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}
){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> mapParam = new HashMap<String,String>();
// 设置参数
// pagesize 每页多少行
mapParam.put("pagesize", "20");
// pageindex 页码
mapParam.put("pageindex", "2");
return mapParam;
}
};
mRequestQueue.add(jsonRequest);
3.ImageRequest
public void showImgByImageReq(){
ImageRequest imageRequest = new ImageRequest("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png",
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
ivImageReq.setImageBitmap(response);
}
}, 500, 500, ImageView.ScaleType.CENTER, Bitmap.Config.ARGB_8888,
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
mRequestQueue.add(imageRequest);
}
- ImageLoad
相比ImageRequest,可以设置内存缓存,可以设置加载和失败时默认显示的图片
可以使用lrucache作为内存缓存
protected void
imageLoad
() {
ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String url) {
return MyApp.cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
MyApp.cache.put(url, bitmap);
}
};
ImageLoader imageLoader = new ImageLoader(MyApp.queue, imageCache);
ImageLoader.ImageListener listener = ImageLoader.getImageListener(ivTest,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
imageLoader.get("http://artcle.fd.zol-img.com.cn/t_s640x2000/g1/M07/0C/0D/Cg-4jVOpQWmIVPnYAAHFv0U3gXkAAOjOwAtyyUAAcXX661.jpg",
listener);
}
也可以自定义listener:
isImmediate标志是从内存缓存中加载还是从网络(或文件缓存中)加载
imageLoader.get("http://img1.goepe.com/201303/1362711681_6600.jpg",
new ImageLoader.ImageListener() {
@Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
if (isImmediate) {
Logger.d("从内存缓存加载");
} else {
Logger.d("从网络加载");
}
ivTest.setImageBitmap(response.getBitmap());
}
@Override
public void onErrorResponse(VolleyError error) {
}
});
- NetworkImageView
private void showNetImg() {
ImageLoader imageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});
mNetworkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
mNetworkImageView.setErrorImageResId(R.mipmap.ic_launcher);
mNetworkImageView.setImageUrl("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png",
imageLoader);
}
五、volley架构和源码分析
1.架构:
RequestQueue.java:
调用
newRequestQueue时,会调用RequestQueue的start方法
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
CacheDispatcher是缓存查找线程,mCacheQueue是缓存队列,mNetworkQueue是网络下载队列,CacheDispatcher从mCacheQueue中拿request,看是否已经缓存,如果缓存,就直接读取缓存获取数据,如果没有缓存,则放入mNetworkQueue进行网络下载
NetworkDispatcher是网络下载线程,是一个线程池,默认4个线程
2.缓存
request的缓存和网络请求真正执行者
在2.3之前的版本中,Http请求是通过httpClient实现,在2.3以后的版本中是通过HttpURLConnection实现,因为在2.3之前的版本中HttpURLConnection非常不稳定
request只有文件缓存,位置:/data/data/包名/cache/volley中
Volley.java
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
// No maximum size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else
{
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();
return queue;
}
ImageLoader内部使用的还是ImageRequest,加了内存缓存机制,所以是三级缓存
- 练习题—修改volley源码,把本地缓存路径设置到”/sdcard/volley”中
- 练习题--百度apistore(根据文档集成并使用):http://apistore.baidu.com/ 文档下载地址:http://bbs.apistore.baidu.com/forum.php?mod=viewthread&tid=734&page=1&extra=#pid1229