本系列主要记录学习android开发网络请求和图片加载框架的使用。
网络操作时官方一般都会介绍HttpClient以及HttpConnection这两个包。前者是apache的开源库,后者是android自带的api。二者进行一个比较,谷歌在官方文档已经说明了,建议在2.3以及以上版本使用 HttpConnection。具体原因呢,是因为对2.1和2.2版本,HttpURLConnection有那么几个Bug,所以建议用Apache 的HTTP Client;之后的版本,建议用HttpURLConnection。android 开发团队不应该维护该库而是转投更为轻量级的httpurlconnection。
当我们开发企业级应用的时候,一般都会选择使用已经封装好的http框架。开源的比较流行的有:
1、volley 官方推出的网络请求框架
下载地址:https://android.googlesource.com/platform/frameworks/volley
下载地址:https://github.com/loopj/android-async-http
官方文档:http://loopj.com/android-async-http/
demo地址:https://github.com/loopj/android-async-http/tree/1.4.9/sample/src/main/java/com/loopj/android/http/sample
3、koush/AndroidAsync 基于nio的异步通信库
下载地址:https://github.com/koush/AndroidAsync
4. Asynchronous Http Client for Android Android异步Http请求
项目地址:https://github.com/loopj/android-async-http
文档介绍:http://loopj.com/android-async-http/
5. android-query 异步加载,更少代码完成Android加载
项目地址:https://github.com/androidquery/androidquery或https://code.google.com/p/android-query/
文档介绍:https://code.google.com/p/android-query/#Why_AQuery?
Demo地址:https://play.google.com/store/apps/details?id=com.androidquery
特点:https://code.google.com/p/android-query/#Why_AQuery?
6. Async Http Client Java异步Http请求
项目地址:https://github.com/AsyncHttpClient/async-http-client
文档介绍:http://sonatype.github.io/async-http-client/
7. Ion 支持图片、json、http post等异步请求
项目地址:https://github.com/koush/ion
文档介绍:https://github.com/koush/ion#more-examples
8. HttpCache Http缓存
项目地址:https://github.com/Trinea/AndroidCommon
Demo地址:https://github.com/Trinea/TrineaDownload/blob/master/TrineaAndroidDemo.apk?raw=true
Demo代码:https://github.com/Trinea/AndroidDemo/blob/master/src/cn/trinea/android/demo/HttpCacheDemo.java
9. Http Request
项目地址:https://github.com/kevinsawicki/http-request
文档介绍:https://github.com/kevinsawicki/http-request#examples
10. okhttp square开源的http工具类
项目地址:https://github.com/square/okhttp
文档介绍:http://square.github.io/okhttp/
11. Retrofit RESTFUL API设计
项目地址:https://github.com/square/retrofit
文档介绍:http://square.github.io/retrofit/
图片加载框架:
1. Android-Universal-Image-Loader 图片缓存
目前使用最广泛的图片缓存,支持主流图片缓存的绝大多数特性。
项目地址:https://github.com/nostra13/Android-Universal-Image-Loader
Demo地址:https://github.com/Trinea/TrineaDownload/blob/master/universal-imageloader-demo.apk?raw=true
文档介绍:http://www.intexsoft.com/blog/item/74-universal-image-loader-part-3.html
2. picasso square开源的图片缓存
项目地址:https://github.com/square/picasso
文档介绍:http://square.github.io/picasso/
3. ImageCache 图片缓存,包含内存和Sdcard缓存
项目地址:https://github.com/Trinea/AndroidCommon
Demo地址:https://github.com/Trinea/TrineaDownload/blob/master/TrineaAndroidDemo.apk?raw=true
文档介绍:http://www.trinea.cn/?p=704
项目地址:https://github.com/facebook/fresco
文档介绍:https://code.facebook.com/posts/366199913563917(译文: http://android.jobbole.com/80922/)
Glide的详细介绍:http://www.oschina.net/p/glide
Glide的下载地址:https://github.com/bumptech/glide
1. Volley简介
除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
下图所示的这些应用都是属于数据量不大,但网络通信频繁的,因此非常适合使用Volley。
前面已经说过,Volley的用法非常简单,那么我们就从最基本的HTTP通信开始学习吧,即发起一条HTTP请求,然后接收HTTP响应。首先需要获取到一个RequestQueue对象,可以调用如下方法获取到:
RequestQueue mQueue = Volley.newRequestQueue(context);
注意这里拿到的RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
接下来为了要发出一条HTTP请求,我们还需要创建一个StringRequest对象,如下所示:
StringRequest stringRequest =new StringRequest("http://www.baidu.com",
new Response.Listener() {
@Override
public voidon Response(String response) {
Log.d("TAG", response);
}
},new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
可以看到,这里new出了一个StringRequest对象,StringRequest的构造函数需要传入三个参数,第一个参数就是目标服务器的URL地址,第二个参数是服务器响应成功的回调,第三个参数是服务器响应失败的回调。其中,目标服务器地址我们填写的是百度的首页,然后在响应成功的回调里打印出服务器返回的内容,在响应失败的回调里打印出失败的详细信息。
最后,将这个StringRequest对象添加到RequestQueue里面就可以了,如下所示:
mQueue.add(stringRequest);
另外,由于Volley是要访问网络的,因此不要忘记在你的AndroidManifest.xml中添加如下权限:
好了,就是这么简单,如果你现在运行一下程序,并发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
这样的话,一个最基本的HTTP发送与响应的功能就完成了。你会发现根本还没写几行代码就轻易实现了这个功能,主要就是进行了以下三步操作:
1. 创建一个RequestQueue对象。
2. 创建一个StringRequest对象。
3. 将StringRequest对象添加到RequestQueue里面。
不过大家都知道,HTTP的请求类型通常有两种,GET和POST,刚才我们使用的明显是一个GET请求,那么如果想要发出一条POST请求应该怎么做呢?StringRequest中还提供了另外一种四个参数的构造函数,其中第一个参数就是指定请求类型的,我们可以使用如下方式进行指定:
StringRequest stringRequest =newStringRequest(Method.POST, url, listener, errorListener);
可是这只是指定了HTTP请求方式是POST,那么我们要提交给服务器的参数又该怎么设置呢?很遗憾,StringRequest中并没有提供设置POST参数的方法,但是当发出POST请求的时候,Volley会尝试调用StringRequest的父类——Request中的getParams()方法来获取POST参数,那么解决方法自然也就有了,我们只需要在StringRequest的匿名类中重写getParams()方法,在这里设置POST参数就可以了,代码如下所示:
StringRequest stringRequest =new StringRequest(Method.POST, url, listener, errorListener) {
@Override
protected Map getParams() throws AuthFailureError {
Map map =newHashMap();
map.put("params1","value1");
map.put("params2","value2");
returnmap;
}
};
学完了最基本的StringRequest的用法,我们再来进阶学习一下JsonRequest的用法。类似于StringRequest,JsonRequest也是继承自Request类的,不过由于JsonRequest是一个抽象类,因此我们无法直接创建它的实例,那么只能从它的子类入手了。JsonRequest有两个直接的子类,JsonObjectRequest和JsonArrayRequest,从名字上你应该能就看出它们的区别了吧?一个是用于请求一段JSON数据的,一个是用于请求一段JSON数组的。
至于它们的用法也基本上没有什么特殊之处,先new出一个JsonObjectRequest对象,如下所示:
JsonObjectRequest jsonObjectRequest =new JsonObjectRequest(url,null,
newResponse.Listener() {
@Override
public voidon Response(JSONObject response) {
Log.d("TAG", response.toString());
}
},newResponse.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
最后再将这个JsonObjectRequest对象添加到RequestQueue里就可以了,如下所示:
mQueue.add(jsonObjectRequest);
由此可以看出,服务器返回给我们的数据确实是JSON格式的,并且onResponse()方法中携带的参数也正是一个JSONObject对象,之后只需要从JSONObject对象取出我们想要得到的那部分数据就可以了。
2、OkHttp是一个高效的Http客户端,有如下的特点:
支持HTTP2/SPDY黑科技
socket自动选择最好路线,并支持自动重连
拥有自动维护的socket连接池,减少握手次数
拥有队列线程池,轻松写并发
拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩,LOGGING)
基于Headers的缓存策略
源码分析地址:http://www.jianshu.com/p/aad5aacd79bf
使用教程:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html
基本使用
privateRequest request;
private static OkHttpClient client =new OkHttpClient();
/**
* 在这里直接设置连接超时,静态方法内,在构造方法被调用前就已经初始话了
*/
static{
client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
client.newBuilder().readTimeout(10, TimeUnit.SECONDS);
client.newBuilder().writeTimeout(10, TimeUnit.SECONDS);
}
//get请求同步方法
new Thread( new Runnable ( ) {
@Override
public void run( ) {
try{
request =new Request.Builder( ).url(Contants.SYNC_URL).build( );
Response response = client.newCall(request).execute( );
result = response.body( ).string( );
runOnUiThread(new Runnable( ) {
@Override public void run( ) {
tvtext.setText(result);
Log.d("MainActivity","hello");
}
});
}catch(Exception e) {
e.printStackTrace();
}
}
}).start();
//异步GET:
new Thread( new Runnable( ) {
@Override public void run( ) {
request =new Request.Builder().url(Contants.ASYNC_URL).build( );
client.newCall(request).enqueue(new Callback() {
/**
* A call is a request that has been prepared for execution. A call can be canceled. As this object
* represents a single request/response pair (stream), it cannot be executed twice.
*@paramcall 是一个接口, 是一个准备好的可以执行的request
* 可以取消,对位一个请求对象,只能单个请求 @parame
*/
@Override public void onFailure(Call call, IOException e) {
Log.d("MainActivity","请求失败");
}
/**
*@paramcall
*@paramresponse 是一个响应请求
*@throwsIOException
*/
@Override
public void onResponse(Call call, Response response)throws IOException {
/**
* 通过拿到response这个响应请求,然后通过body().string(),拿到请求到的数据
* 这里最好用string() 而不要用toString()
* toString()每个类都有的,是把对象转换为字符串
* string()是把流转为字符串
*/
result = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run( ) {
tvtext.setText(result);
}
});
}
});
}
}).start();
//文件下载地址
String url ="your_URL";
request =new Request.Builder().url(url).build();
OkHttpClient client =newOkHttpClient();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response)throws IOException {
//把请求成功的response转为字节流
InputStream inputStream = response.body().byteStream();
/**
* 在这里要加上权限 在mainfests文件中
*/
//在这里用到了文件输出流
FileOutputStream fileOutputStream =newFileOutputStream(newFile("/sdcard/logo.jpg"));
byte[] buffer =newbyte[2048];//定义一个字节数组
int len =0;
while((len = inputStream.read(buffer)) != -1) {//写出到文件
fileOutputStream.write(buffer,0, len);
}
fileOutputStream.flush();//关闭输出流
Log.d("wuyinlei","文件下载成功...");
}
});
未完待续!!!!