Android2.2之前,最佳实践是采用HttpClient;Android 2.2版本之后,HttpURLConnection则是最佳的选择。在Android 5.0则全面废弃了HttpClient。
HttpURLConnection使用起来比较麻烦,Gooogle I/O 2013发布的一个处理和缓存网络请求的库即Volley。Volley的Socket通讯由HttpURLConnection负责,同时添加了多种上层封装。
Volley适合小而快的数据传输。Volley应该是简化了网络通信的一些开发,特别是针对以下两种情况:
• JSON对象
• 图片加载
Volley总共有3层架构。总得来说就是第1层是UI主线程,第2层是硬盘Cache层,第3层是PriorityBlockingQueue和线程池实现的“生产者-消费者”模型。最后将结果通知会UI主线程本质上是“Handler”机制。
解释该架构的文章比较多,更具体的内容可参见下一节的相关博客。
Google官方Volley框架的4节Training
Android开源项目推荐之「网络请求哪家强」
volley源码解析(一)–volley的使用和架构
volley源码解析(二)–Request类的介绍
volley源码解析(四)–CacheDispatcher从缓存中获取数据
volley源码解析(五)–NetworkDispatcher从网络中获取数据
volley源码解析(六)–HurlStack与HttpClientStack之争
volley源码解析(七)–最终目的之Response
官方Training上有这么一段话
Volley is not suitable for large download or streaming operations, since Volley holds all responses in memory during parsing. For large download operations, consider using an alternative like DownloadManager.
即:在大量下载和流量操作方面Volley不适合,因为Volley在解析阶段在内存中保存了所有响应。对于大量的下载操作,应该使用DownloadManager。
另外一点注意,默认的Volley的响应结果都在UI主线程执行。当然可以重载来改变这一点。具体参考“volley 如何将返回结果放在非主线程?”。
(1)StringRequest
RequestQueue queue=Volley.newRequestQueue(this);
String url = "http://www.baidu.com";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener() {
@Override
public void onResponse(String s) {
mTextView.setText("Response is: " + s.substring(0, 500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
mTextView.setText("That didn't work!");
}
});
stringRequest.setTag(TAG);
执行:
queue.add(stringRequest);
(2)ImageRequest
如果要求整个下载功能在应用的生命周期全过程,可以提供一个单例类。这里也把带有内存缓存功能的ImageLoader封装进去了。
/** * Created by CaoYF on 2016/8/16. */
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mCtx;
private MySingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache
cache = new LruCache(20);
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public void addToRequestQueue(Request req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
然后用这个单例类来请求并加载图片。
String url2 = "http://i.imgur.com/7spzG.png";
// Retrieves an image specified by the URL, displays it in the UI.
ImageRequest imageRequest = new ImageRequest(url2,
new Response.Listener() {
@Override
public void onResponse(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
}
}, 0, 0, null,
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
执行
MySingleton.getInstance(MainActivity.this).addToRequestQueue(imageRequest);
(3)JSONObject
这里请求一个北京的天气预报,由于结果不是UTF-8,这里重写了JsonObjectRequest的parseNetworkResponse函数。
String url3 = "http://wthrcdn.etouch.cn/weather_mini?citykey=101010100";
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url3, null, new Response.Listener() {
@Override
public void onResponse(JSONObject response) {
mTextView.setText("Response: " + response.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
mTextView.setText("Response: error");
}
}) {
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
JSONObject jsonObject;
try {
jsonObject = new JSONObject(new String(response.data,"UTF-8"));
return Response.success(jsonObject, HttpHeaderParser.parseCacheHeaders(response));
} catch (JSONException e) {
e.printStackTrace();
return Response.error(new ParseError(e));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return Response.error(new ParseError(e));
}
}
};
执行
MySingleton.getInstance(MainActivity.this).addToRequestQueue(jsObjRequest);
(4)自定义请求类型
如果需要自定义请求类型,需要继承Request 并重写部分函数,具体参考Google官方Volley框架的4节Training最后一节的内容“Implementing a Custom Request”。