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