Android之OkHttp詳解(非原創)


文章大綱

一、OkHttp簡介
二、OkHttp簡單使用
三、OkHttp封裝
四、項目源碼下載

 

一、OkHttp簡介

1. 什么是OkHttp

  一般在Java平台上,我們會使用Apache HttpClient作為Http客戶端,用於發送 HTTP 請求,並對響應進行處理。比如可以使用http客戶端與第三方服務(如SSO服務)進行集成,當然還可以爬取網上的數據等。OKHttp與HttpClient類似,也是一個Http客戶端,提供了對 HTTP/2 和 SPDY 的支持,並提供了連接池,GZIP 壓縮和 HTTP 響應緩存功能。

2. OkHttp優點

(1)支持HTTP2/SPDY(SPDY是Google開發的基於TCP的傳輸層協議,用以最小化網絡延遲,提升網絡速度,優化用戶的網絡使用體驗)
(2)socket自動選擇最好路線,並支持自動重連,擁有自動維護的socket連接池,減少握手次數,減少了請求延遲,共享Socket,減少對服務器的請求次數
(3)基於Headers的緩存策略減少重復的網絡請求
(4)擁有Interceptors輕松處理請求與響應(自動處理GZip壓縮)

3. OkHttp功能

(1)一般的get請求
(2)一般的post請求
(3)基於Http的文件上傳
(4)文件下載
(5)上傳下載的進度回調
(6)加載圖片
(7)支持請求回調,直接返回對象、對象集合
(8)支持session的保持
(9)支持自簽名網站https的訪問,提供方法設置下證書就行
(10)支持取消某個請求

3. OkHttp使用步驟

(1)get請求的步驟,首先構造一個Request對象,參數最起碼有個url,當然你可以通過Request.Builder設置更多的參數比如:header、method等。
(2)然后通過request的對象去構造得到一個Call對象,類似於將你的請求封裝成了任務,既然是任務,就會有execute()和cancel()等方法。
(3)最后,我們希望以異步的方式去執行請求,所以我們調用的是call.enqueue,將call加入調度隊列,然后等待任務執行完成,我們在Callback中即可得到結果。
(4)onResponse回調的參數是response,一般情況下,比如我們希望獲得返回的字符串,
可以通過response.body().string()獲取;如果希望獲得返回的二進制字節數組,則調用response.body().bytes();如果你想拿到返回的inputStream,則調用response.body().byteStream()
(5)看到這,你可能會奇怪,竟然還能拿到返回的inputStream,看到這個最起碼能意識到一點,這里支持大文件下載,有inputStream我們就可以通過IO的方式寫文件。不過也說明一個問題,這個onResponse執行的線程並不是UI線程。的確是的,如果你希望操作控件,還是需要使用handler等
(6)okHttp還支持GJson的處理方式
(7)okhttp支持同步請求和異步請求,Call call = client.newCall(request);為同步請求,發送請求后,就會進入阻塞狀態,知道收到響應call.enqueue(new Callback()為異步請求
(8)在okhttp3.Callback的回調方法里面有個參數是Call 這個call可以單獨取消相應的請求,隨便在onFailure或者onResponse方法內部執行call.cancel()都可以。如果想取消所有的請求,則可以okhttpclient.dispatcher().cancelAll();

二、OkHttp簡單使用

1. 進行get請求

/** * 原始的get請求 * * @author 吳曉暢 * */ public class OkHttpGet { public void get() { //1.okhttpClient對象 OkHttpClient okHttpClient = new OkHttpClient.Builder(). //在這里,還可以設置數據緩存等 //設置超時時間 connectTimeout(15, TimeUnit.SECONDS). readTimeout(20, TimeUnit.SECONDS). writeTimeout(20, TimeUnit.SECONDS). //錯誤重連 retryOnConnectionFailure(true). build(); //2構造Request, //builder.get()代表的是get請求,url方法里面放的參數是一個網絡地址 Request.Builder builder = new Request.Builder(); Request request = builder.get().url("http://www.baidu.com/").build(); //3將Request封裝成call Call call = okHttpClient.newCall(request); //4,執行call,這個方法是異步請求數據 call.enqueue(new Callback() { @Override public void onFailure(Call arg0, IOException arg1) { //失敗調用 } @Override //由於OkHttp在解析response的時候依靠的是response頭信息當中的Content-Type字段來判斷解碼方式 //OkHttp會使用默認的UTF-8編碼方式來解碼 //這里使用的是異步加載,如果需要使用控件,則在主線程中調用 public void onResponse(Call arg0, Response arg1) throws IOException { //成功調用 } }); } } 

2. 進行post請求

/** * 使用okhttp進行post請求 * * @author 吳曉暢 * */ public class OkHttpPost { public void initPost() { //1.okhttpClient對象 OkHttpClient okHttpClient = new OkHttpClient.Builder(). //在這里,還可以設置數據緩存等 //設置超時時間 connectTimeout(15, TimeUnit.SECONDS). readTimeout(20, TimeUnit.SECONDS). writeTimeout(20, TimeUnit.SECONDS). //錯誤重連 retryOnConnectionFailure(true). build(); RequestBody requestBodyPost = new FormBody.Builder() .add("page", "1") .add("code", "news") .add("pageSize", "20") .add("parentid", "0") .add("type", "1") .build(); Request requestPost = new Request.Builder() .url("www.baidu.com") .post(requestBodyPost) .build(); okHttpClient.newCall(requestPost).enqueue(new Callback() { @Override public void onFailure(Call arg0, IOException arg1) { // TODO Auto-generated method stub } @Override public void onResponse(Call arg0, Response arg1) throws IOException { //okHttp還支持GJson的處理方式 //在這里可以進行List<bean>和bean處理 } }); } } 

3. 進行圖片上傳和下載

/** * 使用OkHttp進行圖片上傳和下載 * * @author 吳曉暢 * */ public class OkHttpPicture { public void getPicture() { //1.創建一個okhttpclient對象 OkHttpClient okHttpClient = new OkHttpClient(); //2.創建Request.Builder對象,設置參數,請求方式如果是Get,就不用設置,默認就是Get Request request = new Request.Builder() .url("www.baidu.com") .build(); //3.創建一個Call對象,參數是request對象,發送請求 Call call = okHttpClient.newCall(request); //4.異步請求,請求加入調度 call.enqueue(new Callback() { @Override public void onFailure(Call arg0, IOException arg1) { // TODO Auto-generated method stub } @Override public void onResponse(Call arg0, Response arg1) throws IOException { // //得到從網上獲取資源,轉換成我們想要的類型 // byte[] Picture_bt = response.body().bytes(); // //通過handler更新UI // Message message = handler.obtainMessage(); // message.obj = Picture_bt; // message.what = SUCCESS; // handler.sendMessage(message); } }); } public void shangChuanPicture() { OkHttpClient mOkHttpClent = new OkHttpClient(); //獲取sd卡中的文件 File file = new File(Environment.getExternalStorageDirectory()+"/HeadPortrait.jpg"); MultipartBody.Builder builder = new MultipartBody.Builder() //設置類型 .setType(MultipartBody.FORM) //設置正文內容 .addFormDataPart("img", "HeadPortrait.jpg", RequestBody.create(MediaType.parse("image/png"), file)); RequestBody requestBody = builder.build(); Request request = new Request.Builder() .url("www.baidu.com") .post(requestBody) .build(); Call call = mOkHttpClent.newCall(request); } } 

3. 攔截器使用

什么是攔截器
  首先我們需要了解什么事攔截器。打個比方,鏢局押着一箱元寶在行走在一個山間小路上,突然從山上下來一群山賊攔住了鏢局的去路,將鏢局身上值錢的東西搜刮干凈后將其放行。其中山賊相當於攔截器,鏢局相當於一個正在執行任務的網絡請求,請求中的參數就是鏢局攜帶的元寶。攔截器可以將網絡請求攜帶的參數進行修改驗證,然后放行。這里面其實設計了AOP編程的思想(面向切面編程)。
  在介紹攔截器的作用和好處之前,我們還是要回到山賊這個角色上,如果讓你做一次山賊,你會在什么地方埋伏?肯定是在鏢局必經之路上埋伏。也就是說,攔截器就是在所有的網絡請求的必經之地上進行攔截。
(1)攔截器可以一次性對所有的請求和返回值進行修改。
(2)攔截器可以一次性對請求的參數和返回的結果進行編碼,比如統一設置為UTF-8.
(3)攔截器可以對所有的請求做統一的日志記錄,不需要在每個請求開始或者結束的位置都添加一個日志操作。
(4)其他需要對請求和返回進行統一處理的需求….

OkHttp中攔截器分類
OkHttp中的攔截器分2個:APP層面的攔截器(Application Interception)、網絡請求層面的攔截器(Network Interception)
(1)Application Interceptor是在請求執行剛開始,還沒有執行OkHttp的核心代碼前進行攔截,Application攔截器的作用:
1)不需要擔心是否影響OKHttp的請求策略和請求速度。
2)即使是從緩存中取數據,也會執行Application攔截器。
3)允許重試,即Chain.proceed()可以執行多次。(當然請不要盲目執行多次,需要加入你的邏輯判斷)
(2)Network Interception是在連接網絡之前
1)可以修改OkHttp框架自動添加的一些屬性(當然最好不要修改)。
2)可以觀察最終完整的請求參數(也就是最終服務器接收到的請求數據和熟悉)

使用注意點
如果對攔截器不是很熟的同學,開發過程中,建議使用Application Interception。這樣避免對OkHttp請求策略的破壞。

常見實際場景
(1)對請求參數進行統一加密處理。
(2)攔截不符合規則的URL。
(3)對請求或者返回參數設置統一的編碼方式
(4)其它…。

代碼實操

public class OkHttpLanJieQi { /** * 應用攔截器 */ Interceptor appInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //———請求之前要做的事情———— HttpUrl url = request.url(); String s = url.url().toString(); Response response = chain.proceed(request); //———請求之后要做事情———— Log.d("aa","app interceptor:begin"); return response; } }; /** * 網絡攔截器 */ Interceptor networkInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //———請求之前要做的事情———— Response response = chain.proceed(request); //———請求之后要做事情———— return response; } }; /** * 進行get請求,並配置攔截器 */ public void initGet() { OkHttpClient okHttpClient = new OkHttpClient .Builder() .addInterceptor(appInterceptor)//Application攔截器 .addNetworkInterceptor(networkInterceptor)//Network攔截器 .build(); //2構造Request, //builder.get()代表的是get請求,url方法里面放的參數是一個網絡地址 Request.Builder builder = new Request.Builder(); Request request = builder.get().url("http://www.baidu.com/").build(); //3將Request封裝成call Call call = okHttpClient.newCall(request); //4,執行call,這個方法是異步請求數據 call.enqueue(new Callback() { @Override public void onFailure(Call arg0, IOException arg1) { //失敗調用 } @Override //由於OkHttp在解析response的時候依靠的是response頭信息當中的Content-Type字段來判斷解碼方式 //OkHttp會使用默認的UTF-8編碼方式來解碼 //這里使用的是異步加載,如果需要使用控件,則在主線程中調用 public void onResponse(Call arg0, Response arg1) throws IOException { //成功調用 } }); } } 

三、OkHttp封裝

1. 自行簡單封裝

/** * okhttp操作進行封裝 * * @author 吳曉暢 * */ public class OkHttp { public void get(String url, Callback callback) { //1.okhttpClient對象 OkHttpClient okHttpClient = new OkHttpClient.Builder(). //在這里,還可以設置數據緩存等 //設置超時時間 connectTimeout(15, TimeUnit.SECONDS). readTimeout(20, TimeUnit.SECONDS). writeTimeout(20, TimeUnit.SECONDS). addInterceptor(appInterceptor).//Application攔截器 //錯誤重連 retryOnConnectionFailure(true). build(); //2構造Request, //builder.get()代表的是get請求,url方法里面放的參數是一個網絡地址 Request.Builder builder = new Request.Builder(); Request request = builder.get().url(url).build(); //3將Request封裝成call Call call = okHttpClient.newCall(request); //4,執行call,這個方法是異步請求數據 call.enqueue(callback); } public void post(String url, List<String> list, Callback callback, RequestBody requestBody) { //1.okhttpClient對象 OkHttpClient okHttpClient = new OkHttpClient.Builder(). //在這里,還可以設置數據緩存等 //設置超時時間 connectTimeout(15, TimeUnit.SECONDS). addInterceptor(appInterceptor).//Application攔截器 readTimeout(20, TimeUnit.SECONDS). writeTimeout(20, TimeUnit.SECONDS). //錯誤重連 retryOnConnectionFailure(true). build(); RequestBody requestBodyPost = requestBody; Request requestPost = new Request.Builder() .url(url) .post(requestBodyPost) .build(); okHttpClient.newCall(requestPost).enqueue(callback); } /** * 應用攔截器 */ Interceptor appInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //———請求之前要做的事情———— Response response = chain.proceed(request); //———請求之后要做事情———— return response; } }; } 

2. Android--OKHttpUtils框架封裝

簡介
  OKHttpUtils:一個專注於讓網絡請求更簡單的網絡請求框架,對於任何形式的網絡請求只需要一行代碼。它是OKHttp的一次二次封裝,封裝的目的是讓網絡請求更加方便。

OKHttpUtils優勢
(1)性能高,使用主流的okhttp的進行封裝
  OKHttp我們知道它支持http2和socket的重連。自動選擇最好的路線,擁有自己維護socket維護的連接池。可以減少TCP的握手次數,同時它擁有隊列線程池可以輕松的並發請求。
(2)特有的網絡緩存模式
  OKHttpUtils是大多數網絡框架不具備的,比如我們公司的網絡老板要求不僅在有網的情況下,進行展示網絡數據,在無網的情況下使用緩存數據。這時候我們使用普通網絡請求,就需要大量的判斷。當前是否有網和無網狀態,根據不同的狀態保存不同的數據。然后再決定是否使用緩存。但是這是一個通用的寫法。於是OKHttpUtils使用自動網絡緩存模式。讓用戶只關注數據處理。
(3)方便易用的擴展接口
  可以添加全局的公共參數、全局的攔截器、全局的超時時間,更可以對單個請求定制攔截器。請求參數修改等等。
(4)強大的Cookie的保存策略
  在客戶端對Cookie的獲取不是一個特別簡單的事情,Cookie全程自動管理,並且提供了額外的Cookie管理方法,引入額外的自動管理中,添加任何你想創建的Cookie。

依賴包導入

compile 'com.zhy:okhttputils:2.0.0' 

進行get請求

    private String get(String url) throws IOException { Request request = new Request.Builder() .url(url)//傳url .build();//創建 //把request傳進client //execute()執行線程 Response response = client.newCall(request).execute(); return response.body().string(); } 

進行post請求

    private String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); return response.body().string(); } 

使用okhttp-utils請求單張圖片

public void getImage() { tv_result.setText(""); String url = "http://images.csdn.net/20150817/1.jpg"; OkHttpUtils .get()// .url(url)// .tag(this)// .build()// .connTimeOut(20000)//鏈接超時 .readTimeOut(20000)//讀取超時 .writeTimeOut(20000)//寫入超時 .execute(new BitmapCallback() { @Override public void onError(Call call, Exception e, int id) { tv_result.setText("onError:" + e.getMessage()); } @Override public void onResponse(Bitmap bitmap, int id) { Log.e("TAG", "onResponse:complete"); iv_icon.setImageBitmap(bitmap); } }); } 

使用okhttp-utils上傳多個或者單個文件

 /** * 使用okhttp-utils上傳多個或者單個文件 */ public void multiFileUpload() { //FileUploadServlet String mBaseUrl = "http://192.168.3.27:8080/FileUpload/FileUploadServlet"; File file = new File(Environment.getExternalStorageDirectory(), "tupian.jpg"); File file2 = new File(Environment.getExternalStorageDirectory(), "zanghao.jpg"); if (!file.exists()) { Toast.makeText(OKHttpActivity.this, "文件不存在,請修改文件路徑", Toast.LENGTH_SHORT).show(); return; } // Map<String, String> params = new HashMap<String, String>(); // params.put("username", "黃敏瑩"); // params.put("password", "123"); String url = mBaseUrl; OkHttpUtils.post()// .addFile("mFile", "server_tupian.jpg", file)// .addFile("mFile", "server_zanghao.jpg", file2)//兩個addFile就是多文件上傳,注釋掉一個就是單文件上傳 .url(url) // .params(params)// .build()// .execute(new MyStringCallBack());//回調 } 

回調處理

/** * 用於回調 * @author Mloong * */ private class MyStringCallBack extends StringCallback{ @Override public void onBefore(Request request, int id) { // TODO Auto-generated method stub super.onBefore(request, id); setTitle("loading..."); } @Override public void onAfter(int id) { // TODO Auto-generated method stub super.onAfter(id); setTitle("sample-okhttp"); } //出錯 @Override public void onError(Call arg0, Exception e, int arg2) { e.printStackTrace(); tv_result.setText("onError:"+e.getMessage()); } //成功后回調 @Override public void onResponse(String response, int id) { //顯示文本信息 tv_result.setText("onResponse:"+ response); switch (id) { case 100: Toast.makeText(OKHttpActivity.this, "http", Toast.LENGTH_LONG).show(); break; case 101: Toast.makeText(OKHttpActivity.this, "https", Toast.LENGTH_LONG).show(); break; default: break; } } @Override public void inProgress(float progress, long total, int id) { Log.e(TAG, "inProgress:"+progress); mProgressBar.setProgress((int) (100*progress)); } } 

四、項目源碼下載

鏈接:https://pan.baidu.com/s/1f3eZhmfKakrd9zaGzX8_gQ
密碼:cv4b

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM