本系列主要記錄學(xué)習(xí)android開(kāi)發(fā)網(wǎng)絡(luò)請(qǐng)求和圖片加載框架的使用。
網(wǎng)絡(luò)操作時(shí)官方一般都會(huì)介紹HttpClient以及HttpConnection這兩個(gè)包。前者是apache的開(kāi)源庫(kù),后者是android自帶的api。二者進(jìn)行一個(gè)比較,谷歌在官方文檔已經(jīng)說(shuō)明了,建議在2.3以及以上版本使用 HttpConnection。具體原因呢,是因?yàn)閷?duì)2.1和2.2版本,HttpURLConnection有那么幾個(gè)Bug,所以建議用Apache 的HTTP Client;之后的版本,建議用HttpURLConnection。android 開(kāi)發(fā)團(tuán)隊(duì)不應(yīng)該維護(hù)該庫(kù)而是轉(zhuǎn)投更為輕量級(jí)的httpurlconnection。
當(dāng)我們開(kāi)發(fā)企業(yè)級(jí)應(yīng)用的時(shí)候,一般都會(huì)選擇使用已經(jīng)封裝好的http框架。開(kāi)源的比較流行的有:
1、volley 官方推出的網(wǎng)絡(luò)請(qǐng)求框架
下載地址: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的異步通信庫(kù)
下載地址:https://github.com/koush/AndroidAsync
4. Asynchronous Http Client for Android Android異步Http請(qǐng)求
項(xiàng)目地址:https://github.com/loopj/android-async-http
文檔介紹:http://loopj.com/android-async-http/
5. android-query 異步加載,更少代碼完成Android加載
項(xiàng)目地址: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
特點(diǎn):https://code.google.com/p/android-query/#Why_AQuery?
6. Async Http Client Java異步Http請(qǐng)求
項(xiàng)目地址:https://github.com/AsyncHttpClient/async-http-client
文檔介紹:http://sonatype.github.io/async-http-client/
7. Ion?支持圖片、json、http post等異步請(qǐng)求
項(xiàng)目地址:https://github.com/koush/ion
文檔介紹:https://github.com/koush/ion#more-examples
8. HttpCache Http緩存
項(xiàng)目地址: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
項(xiàng)目地址:https://github.com/kevinsawicki/http-request
文檔介紹:https://github.com/kevinsawicki/http-request#examples
10. okhttp square開(kāi)源的http工具類(lèi)
項(xiàng)目地址:https://github.com/square/okhttp
文檔介紹:http://square.github.io/okhttp/
11. Retrofit RESTFUL API設(shè)計(jì)
項(xiàng)目地址:https://github.com/square/retrofit
文檔介紹:http://square.github.io/retrofit/
圖片加載框架:
1. Android-Universal-Image-Loader 圖片緩存
目前使用最廣泛的圖片緩存,支持主流圖片緩存的絕大多數(shù)特性。
項(xiàng)目地址: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開(kāi)源的圖片緩存
項(xiàng)目地址:https://github.com/square/picasso
文檔介紹:http://square.github.io/picasso/
3. ImageCache 圖片緩存,包含內(nèi)存和Sdcard緩存
項(xiàng)目地址:https://github.com/Trinea/AndroidCommon
Demo地址:https://github.com/Trinea/TrineaDownload/blob/master/TrineaAndroidDemo.apk?raw=true
文檔介紹:http://www.trinea.cn/?p=704
項(xiàng)目地址:https://github.com/facebook/fresco
文檔介紹:https://code.facebook.com/posts/366199913563917(譯文: ? ? ? ? ? ? ? http://android.jobbole.com/80922/)
Glide的詳細(xì)介紹:http://www.oschina.net/p/glide
Glide的下載地址:https://github.com/bumptech/glide
1. Volley簡(jiǎn)介
除了簡(jiǎn)單易用之外,Volley在性能方面也進(jìn)行了大幅度的調(diào)整,它的設(shè)計(jì)目標(biāo)就是非常適合去進(jìn)行數(shù)據(jù)量不大,但通信頻繁的網(wǎng)絡(luò)操作,而對(duì)于大數(shù)據(jù)量的網(wǎng)絡(luò)操作,比如說(shuō)下載文件等,Volley的表現(xiàn)就會(huì)非常糟糕。
下圖所示的這些應(yīng)用都是屬于數(shù)據(jù)量不大,但網(wǎng)絡(luò)通信頻繁的,因此非常適合使用Volley。
前面已經(jīng)說(shuō)過(guò),Volley的用法非常簡(jiǎn)單,那么我們就從最基本的HTTP通信開(kāi)始學(xué)習(xí)吧,即發(fā)起一條HTTP請(qǐng)求,然后接收HTTP響應(yīng)。首先需要獲取到一個(gè)RequestQueue對(duì)象,可以調(diào)用如下方法獲取到:
RequestQueue?mQueue?=?Volley.newRequestQueue(context);
注意這里拿到的RequestQueue是一個(gè)請(qǐng)求隊(duì)列對(duì)象,它可以緩存所有的HTTP請(qǐng)求,然后按照一定的算法并發(fā)地發(fā)出這些請(qǐng)求。RequestQueue內(nèi)部的設(shè)計(jì)就是非常合適高并發(fā)的,因此我們不必為每一次HTTP請(qǐng)求都創(chuàng)建一個(gè)RequestQueue對(duì)象,這是非常浪費(fèi)資源的,基本上在每一個(gè)需要和網(wǎng)絡(luò)交互的Activity中創(chuàng)建一個(gè)RequestQueue對(duì)象就足夠了。
接下來(lái)為了要發(fā)出一條HTTP請(qǐng)求,我們還需要?jiǎng)?chuàng)建一個(gè)StringRequest對(duì)象,如下所示:
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出了一個(gè)StringRequest對(duì)象,StringRequest的構(gòu)造函數(shù)需要傳入三個(gè)參數(shù),第一個(gè)參數(shù)就是目標(biāo)服務(wù)器的URL地址,第二個(gè)參數(shù)是服務(wù)器響應(yīng)成功的回調(diào),第三個(gè)參數(shù)是服務(wù)器響應(yīng)失敗的回調(diào)。其中,目標(biāo)服務(wù)器地址我們填寫(xiě)的是百度的首頁(yè),然后在響應(yīng)成功的回調(diào)里打印出服務(wù)器返回的內(nèi)容,在響應(yīng)失敗的回調(diào)里打印出失敗的詳細(xì)信息。
最后,將這個(gè)StringRequest對(duì)象添加到RequestQueue里面就可以了,如下所示:
mQueue.add(stringRequest);
另外,由于Volley是要訪問(wèn)網(wǎng)絡(luò)的,因此不要忘記在你的AndroidManifest.xml中添加如下權(quán)限:
好了,就是這么簡(jiǎn)單,如果你現(xiàn)在運(yùn)行一下程序,并發(fā)出這樣一條HTTP請(qǐng)求,就會(huì)看到LogCat中會(huì)打印出如下圖所示的數(shù)據(jù)。
這樣的話,一個(gè)最基本的HTTP發(fā)送與響應(yīng)的功能就完成了。你會(huì)發(fā)現(xiàn)根本還沒(méi)寫(xiě)幾行代碼就輕易實(shí)現(xiàn)了這個(gè)功能,主要就是進(jìn)行了以下三步操作:
1. 創(chuàng)建一個(gè)RequestQueue對(duì)象。
2. 創(chuàng)建一個(gè)StringRequest對(duì)象。
3. 將StringRequest對(duì)象添加到RequestQueue里面。
不過(guò)大家都知道,HTTP的請(qǐng)求類(lèi)型通常有兩種,GET和POST,剛才我們使用的明顯是一個(gè)GET請(qǐng)求,那么如果想要發(fā)出一條POST請(qǐng)求應(yīng)該怎么做呢?StringRequest中還提供了另外一種四個(gè)參數(shù)的構(gòu)造函數(shù),其中第一個(gè)參數(shù)就是指定請(qǐng)求類(lèi)型的,我們可以使用如下方式進(jìn)行指定:
StringRequest?stringRequest?=newStringRequest(Method.POST,?url,??listener,?errorListener);
可是這只是指定了HTTP請(qǐng)求方式是POST,那么我們要提交給服務(wù)器的參數(shù)又該怎么設(shè)置呢?很遺憾,StringRequest中并沒(méi)有提供設(shè)置POST參數(shù)的方法,但是當(dāng)發(fā)出POST請(qǐng)求的時(shí)候,Volley會(huì)嘗試調(diào)用StringRequest的父類(lèi)——Request中的getParams()方法來(lái)獲取POST參數(shù),那么解決方法自然也就有了,我們只需要在StringRequest的匿名類(lèi)中重寫(xiě)getParams()方法,在這里設(shè)置POST參數(shù)就可以了,代碼如下所示:
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;
}
};
學(xué)完了最基本的StringRequest的用法,我們?cè)賮?lái)進(jìn)階學(xué)習(xí)一下JsonRequest的用法。類(lèi)似于StringRequest,JsonRequest也是繼承自Request類(lèi)的,不過(guò)由于JsonRequest是一個(gè)抽象類(lèi),因此我們無(wú)法直接創(chuàng)建它的實(shí)例,那么只能從它的子類(lèi)入手了。JsonRequest有兩個(gè)直接的子類(lèi),JsonObjectRequest和JsonArrayRequest,從名字上你應(yīng)該能就看出它們的區(qū)別了吧?一個(gè)是用于請(qǐng)求一段JSON數(shù)據(jù)的,一個(gè)是用于請(qǐng)求一段JSON數(shù)組的。
至于它們的用法也基本上沒(méi)有什么特殊之處,先new出一個(gè)JsonObjectRequest對(duì)象,如下所示:
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);
}
});
最后再將這個(gè)JsonObjectRequest對(duì)象添加到RequestQueue里就可以了,如下所示:
mQueue.add(jsonObjectRequest);
由此可以看出,服務(wù)器返回給我們的數(shù)據(jù)確實(shí)是JSON格式的,并且onResponse()方法中攜帶的參數(shù)也正是一個(gè)JSONObject對(duì)象,之后只需要從JSONObject對(duì)象取出我們想要得到的那部分?jǐn)?shù)據(jù)就可以了。
2、OkHttp是一個(gè)高效的Http客戶(hù)端,有如下的特點(diǎn):
支持HTTP2/SPDY黑科技
socket自動(dòng)選擇最好路線,并支持自動(dòng)重連
擁有自動(dòng)維護(hù)的socket連接池,減少握手次數(shù)
擁有隊(duì)列線程池,輕松寫(xiě)并發(fā)
擁有Interceptors輕松處理請(qǐng)求與響應(yīng)(比如透明GZIP壓縮,LOGGING)
基于Headers的緩存策略
源碼分析地址:http://www.itdecent.cn/p/aad5aacd79bf
使用教程:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html
基本使用
privateRequest request;
private static OkHttpClient client =new OkHttpClient();
/**
* 在這里直接設(shè)置連接超時(shí),靜態(tài)方法內(nèi),在構(gòu)造方法被調(diào)用前就已經(jīng)初始話了
*/
static{
client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
client.newBuilder().readTimeout(10, TimeUnit.SECONDS);
client.newBuilder().writeTimeout(10, TimeUnit.SECONDS);
}
//get請(qǐng)求同步方法
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? 是一個(gè)接口,? 是一個(gè)準(zhǔn)備好的可以執(zhí)行的request ? ? ? ? ? ? ? ?
? *? ? ? ? ? ? ? 可以取消,對(duì)位一個(gè)請(qǐng)求對(duì)象,只能單個(gè)請(qǐng)求 ? @parame ? ? ? ? ? ? ? ? ? ?
?*/
@Override public void onFailure(Call call, IOException e) {
? ? ? ? ? ? ? ? ? ? ? ? Log.d("MainActivity","請(qǐng)求失敗");
}
/**? ? ? ? ? ? ? ? ??
?*@paramcall? ? ? ? ? ? ? ? ? ?
?*@paramresponse? 是一個(gè)響應(yīng)請(qǐng)求? ? ? ? ? ? ? ? ? ??
*@throwsIOException? ? ? ? ? ? ? ? ? ??
?*/
@Override?
public void onResponse(Call call, Response response)throws IOException {
/**
* 通過(guò)拿到response這個(gè)響應(yīng)請(qǐng)求,然后通過(guò)body().string(),拿到請(qǐng)求到的數(shù)據(jù)
* 這里最好用string()? 而不要用toString()
* toString()每個(gè)類(lèi)都有的,是把對(duì)象轉(zhuǎn)換為字符串
* string()是把流轉(zhuǎn)為字符串
*/
? ? ? ? ? ? ?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 {
//把請(qǐng)求成功的response轉(zhuǎn)為字節(jié)流
InputStream inputStream = response.body().byteStream();
/**
* 在這里要加上權(quán)限? 在mainfests文件中
*/
//在這里用到了文件輸出流
FileOutputStream fileOutputStream =newFileOutputStream(newFile("/sdcard/logo.jpg"));
byte[] buffer =newbyte[2048];//定義一個(gè)字節(jié)數(shù)組
int len =0;
while((len = inputStream.read(buffer)) != -1) {//寫(xiě)出到文件
fileOutputStream.write(buffer,0, len);
}
fileOutputStream.flush();//關(guān)閉輸出流
Log.d("wuyinlei","文件下載成功...");
}
});
未完待續(xù)?。。?!