【0131】【okhttp框架解析與應用】

【備註】另一個框架retrofit

1.  網絡框架簡單概述

【cookie】代表請求的用戶身份;java

 

2.網絡框架源碼結構分析

2.1 okhttjp的核心框架

 

2.2 核心類

 

【須要實現的抽象類】android

【實現抽象類-1】formBody只能上傳簡單的key-value數據;發送post請求的時候會構建formBody;json

 【實現抽象類-2】MultipartBody:能夠實現對象類型的數據的上傳;大的文件的上傳;服務器

 

 

【request類】cookie

 

【call】網絡

 

【realCall】session

 

【Header類】app

 

【DNS解析域名的類】框架

【connection相關類】ide

 

【CallBack】返回數據的回調;

【address封裝了請求的數據】

【Cache模塊】

【核心類】核心的方法:sendRequest;

 

【dispatcher分發類】

【流程】dispatcher將call數據放到隊列中,在隊列中依次執行Call,realCall對調用httpEngine,真正的構建connection和request,而後調用connect方法,獲取最終的response;封裝在respBody中,

而後在CallBack的onresponse方法中獲取數據;

【okhttpClient類】全部流程的相互配合使用的是okhttpClient類進行配合的

 

3.網絡框架的簡單使用

 3.1 get請求的使用

3.2 post請求的封裝

4.封裝通用的網絡模塊

 

4.1 listener的封裝

 【回調方法】定義本次的請求的處理會有哪些回調的方法進行處理;

【DisposeDataHandle.java】G:\CommonLibrary-master\CommonHttpLibrary\src\com\okhttp\listener\DisposeDataHandle.java

 1 package com.okhttp.listener;
 2 
 3 /**
 4  * 
 5  *
 6  */
 7 public class DisposeDataHandle
 8 {
 9     public DisposeDataListener mListener = null; //response的響應回調;
10     public Class<?> mClass = null;  //對應的json字節碼文件
11     public String mSource = null;
12 
13     //直接將獲得的json字符串拋到應用層解析;
14     public DisposeDataHandle(DisposeDataListener listener)
15     {
16         this.mListener = listener;
17     }
18 
19     //若是傳遞了對象,就將json文件轉化爲該對象的文件;
20     public DisposeDataHandle(DisposeDataListener listener, Class<?> clazz)
21     {
22         this.mListener = listener;
23         this.mClass = clazz;
24     }
25 
26     public DisposeDataHandle(DisposeDataListener listener, String source)
27     {
28         this.mListener = listener;
29         this.mSource = source;
30     }
31 }

 【封轉的請求參數】以鍵值對的形式進行封裝;G:\CommonLibrary-master\CommonHttpLibrary\src\com\okhttp\request\RequestParams.java

 1 package com.okhttp.request;
 2 
 3 import java.io.FileNotFoundException;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 import java.util.concurrent.ConcurrentHashMap;
 7 
 8 public class RequestParams {
 9 
10     public ConcurrentHashMap<String, String> urlParams = new ConcurrentHashMap<String, String>();
11     public ConcurrentHashMap<String, Object> fileParams = new ConcurrentHashMap<String, Object>();
12 
13     /**
14      * Constructs a new empty {@code RequestParams} instance.
15      */
16     public RequestParams() {
17         this((Map<String, String>) null);
18     }
19 
20     /**
21      * Constructs a new RequestParams instance containing the key/value string
22      * params from the specified map.
23      *
24      * @param source
25      *            the source key/value string map to add.
26      */
27     public RequestParams(Map<String, String> source) {
28         if (source != null) {
29             for (Map.Entry<String, String> entry : source.entrySet()) {
30                 put(entry.getKey(), entry.getValue());
31             }
32         }
33     }
34 
35     /**
36      * Constructs a new RequestParams instance and populate it with a single
37      * initial key/value string param.
38      *
39      * @param key
40      *            the key name for the intial param.
41      * @param value
42      *            the value string for the initial param.
43      */
44     public RequestParams(final String key, final String value) {
45         this(new HashMap<String, String>() {
46             {
47                 put(key, value);
48             }
49         });
50     }
51 
52     /**
53      * Adds a key/value string pair to the request.
54      *
55      * @param key
56      *            the key name for the new param.
57      * @param value
58      *            the value string for the new param.
59      */
60     public void put(String key, String value) {
61         if (key != null && value != null) {
62             urlParams.put(key, value);
63         }
64     }
65 
66     public void put(String key, Object object) throws FileNotFoundException {
67 
68         if (key != null) {
69             fileParams.put(key, object);
70         }
71     }
72 }

 【封裝請求】G:\CommonLibrary-master\CommonHttpLibrary\src\com\okhttp\request\CommonRequest.java

[post請求]

[文件上傳請求]

 

[源碼]G:\CommonLibrary-master\CommonHttpLibrary\src\com\okhttp\request\CommonRequest.java

 1 package com.okhttp.request;
 2 
 3 import java.io.File;
 4 import java.util.Map;
 5 
 6 import okhttp3.FormBody;
 7 import okhttp3.Headers;
 8 import okhttp3.MediaType;
 9 import okhttp3.MultipartBody;
10 import okhttp3.Request;
11 import okhttp3.RequestBody;
12 
13 /**
14  * @author vision
15  * @function build the request
16  * 主要負責對各類請求的文件類型的封裝:get/post/上傳文件類型/下載文件類型;
17  */
18 public class CommonRequest {
19 
20     /**
21      * create the key-value Request
22      *
23      * @function: 將 params拼接在url後面,而後構成Request請求;
24      */
25     public static Request createPostRequest(String url, RequestParams params) {
26         FormBody.Builder mFormBodyBuild = new FormBody.Builder();
27         if (params != null) {
28             for (Map.Entry<String, String> entry : params.urlParams.entrySet()) {
29                 mFormBodyBuild.add(entry.getKey(), entry.getValue());
30             }
31         }
32         FormBody mFormBody = mFormBodyBuild.build();
33         return new Request.Builder().url(url).post(mFormBody).build();
34     }
35 
36     /**
37      * ressemble the params to the url
38      * 
39      * @param url
40      * @param params
41      * @return
42      * @function:建立一個post請求的request請求類型的對象;
43      */
44     public static Request createGetRequest(String url, RequestParams params) {
45         StringBuilder urlBuilder = new StringBuilder(url).append("?");
46         if (params != null) {
47             for (Map.Entry<String, String> entry : params.urlParams.entrySet()) {
48                 urlBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
49             }
50         }
51         return new Request.Builder().url(urlBuilder.substring(0, urlBuilder.length() - 1)).get().build();
52     }
53 
54     /**
55      * 文件上傳請求
56      * 
57      * @return
58      */
59     private static final MediaType FILE_TYPE = MediaType.parse("application/octet-stream");
60 
61     public static Request createMultiPostRequest(String url, RequestParams params) {
62 
63         MultipartBody.Builder requestBody = new MultipartBody.Builder();
64         requestBody.setType(MultipartBody.FORM);
65         if (params != null) {
66 
67             for (Map.Entry<String, Object> entry : params.fileParams.entrySet()) {
68                 //判斷是不是文件;
69                 if (entry.getValue() instanceof File) {
70                     //若是是文件;
71                     requestBody.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + entry.getKey() + "\""),
72                             RequestBody.create(FILE_TYPE, (File) entry.getValue()));
73                 } else if (entry.getValue() instanceof String) {
74                     //若是不是文件,就當作簡單的key-value值建立;
75                     requestBody.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + entry.getKey() + "\""),
76                             RequestBody.create(null, (String) entry.getValue()));
77                 }
78             }
79         }
80         return new Request.Builder().url(url).post(requestBody.build()).build();
81     }
82 }

 【回調的封裝】實現callBack接口;

【CommonJsonCallback.java】對json的回調的處理;G:\CommonLibrary-master\CommonHttpLibrary\src\com\okhttp\response\CommonJsonCallback.java

  1 package com.okhttp.response;
  2 
  3 import java.io.IOException;
  4 import java.util.ArrayList;
  5 
  6 import org.json.JSONObject;
  7 
  8 import com.loopj.android.http.commonhttp.ResponseEntityToModule;
  9 import com.okhttp.exception.OkHttpException;
 10 import com.okhttp.listener.DisposeDataHandle;
 11 import com.okhttp.listener.DisposeDataListener;
 12 import com.okhttp.listener.DisposeHandleCookieListener;
 13 
 14 import android.os.Handler;
 15 import android.os.Looper;
 16 import okhttp3.Call;
 17 import okhttp3.Callback;
 18 import okhttp3.Headers;
 19 import okhttp3.Response;
 20 
 21 /**
 22  * @author vision
 23  * @function 專門處理JSON的回調
 24  */
 25 public class CommonJsonCallback implements Callback {
 26 
 27     /**
 28      * the logic layer exception, may alter in different app
 29      * 【注意】此段代碼是根據公司的服務器的協議進行定製的;不一樣公司不一致;
 30      */
 31     // 有返回則對於http請求來講是成功的,但還有多是業務邏輯上的錯誤
 32     protected final String RESULT_CODE = "ecode";
 33     protected final int RESULT_CODE_VALUE = 0;
 34     protected final String ERROR_MSG = "emsg";
 35     protected final String EMPTY_MSG = "";
 36     protected final String COOKIE_STORE = "Set-Cookie"; // decide the server it
 37                                                         // can has the value of
 38                                                         // set-cookie2
 39 
 40     /**
 41      * the java layer exception, do not same to the logic error
 42      */
 43     protected final int NETWORK_ERROR = -1; // the network relative error
 44     protected final int JSON_ERROR = -2; // the JSON relative error
 45     protected final int OTHER_ERROR = -3; // the unknow error
 46 
 47     /**
 48      * 將其它線程的數據轉發到UI線程
 49      */
 50     private Handler mDeliveryHandler; //數據的轉發
 51     private DisposeDataListener mListener;  //接口;
 52     private Class<?> mClass;  //要轉化爲的字符串的數據;
 53 
 54     public CommonJsonCallback(DisposeDataHandle handle) {
 55         this.mListener = handle.mListener;
 56         this.mClass = handle.mClass;
 57         //須要返回到主線程中,所以須要建立主線程的Looper;
 58         this.mDeliveryHandler = new Handler(Looper.getMainLooper());
 59     }
 60 
 61     //對返回數據的失敗的處理
 62     @Override
 63     public void onFailure(final Call call, final IOException ioexception) {
 64         /**
 65          * 此時還在非UI線程,所以要轉發
 66          */
 67         mDeliveryHandler.post(new Runnable() {
 68             @Override
 69             public void run() {
 70                 //直接回調listener中的onFailure便可;
 71                 mListener.onFailure(new OkHttpException(NETWORK_ERROR, ioexception));
 72             }
 73         });
 74     }
 75 
 76 
 77     @Override
 78     public void onResponse(final Call call, final Response response) throws IOException {
 79         final String result = response.body().string();
 80         final ArrayList<String> cookieLists = handleCookie(response.headers());
 81         mDeliveryHandler.post(new Runnable() {
 82             @Override
 83             public void run() {
 84                 handleResponse(result);  //見105行的方法的處理;
 85                 /**
 86                  * handle the cookie
 87                  */
 88                 if (mListener instanceof DisposeHandleCookieListener) {
 89                     ((DisposeHandleCookieListener) mListener).onCookie(cookieLists);
 90                 }
 91             }
 92         });
 93     }
 94 
 95     private ArrayList<String> handleCookie(Headers headers) {
 96         ArrayList<String> tempList = new ArrayList<String>();
 97         for (int i = 0; i < headers.size(); i++) {
 98             if (headers.name(i).equalsIgnoreCase(COOKIE_STORE)) {
 99                 tempList.add(headers.value(i));
100             }
101         }
102         return tempList;
103     }
104 
105     private void handleResponse(Object responseObj) {
106         if (responseObj == null) {
107             mListener.onFailure(new OkHttpException(NETWORK_ERROR, EMPTY_MSG));
108             return;
109         }
110 
111         try {
112             JSONObject result = new JSONObject(responseObj.toString());
113             if (result.has(RESULT_CODE)) {
114                 if (result.optInt(RESULT_CODE) == RESULT_CODE_VALUE) {
115                     //若是沒有傳入返回的對象;
116                     if (mClass == null) {
117                         //直接返回到應用層;
118                         mListener.onSuccess(result);
119                     } else {
120                         //對json字符串進行解析;
121                         Object obj = ResponseEntityToModule.parseJsonObjectToModule(result, mClass);
122                         if (obj != null) {
123                             //json數據解析成功,返回給應用層;
124                             mListener.onSuccess(obj);
125                         } else {
126                             //解析失敗,拋出異常;
127                             mListener.onFailure(new OkHttpException(JSON_ERROR, EMPTY_MSG));
128                         }
129                     }
130                 } else {
131                     if (result.has(ERROR_MSG)) {
132                         mListener.onFailure(
133                                 new OkHttpException(result.optInt(RESULT_CODE), result.optString(ERROR_MSG)));
134                     } else {
135                         mListener.onFailure(new OkHttpException(result.optInt(RESULT_CODE), EMPTY_MSG));
136                     }
137                 }
138             } else {
139                 if (result.has(ERROR_MSG)) {
140                     mListener.onFailure(new OkHttpException(OTHER_ERROR, result.optString(ERROR_MSG)));
141                 }
142             }
143         } catch (Exception e) {
144             mListener.onFailure(new OkHttpException(OTHER_ERROR, e.getMessage()));
145             e.printStackTrace();
146         }
147     }
148 }

 

【對文件的解析的回調的處理】

  1 package com.okhttp.response;
  2 
  3 import java.io.File;
  4 import java.io.FileOutputStream;
  5 import java.io.IOException;
  6 import java.io.InputStream;
  7 
  8 import com.okhttp.exception.OkHttpException;
  9 import com.okhttp.listener.DisposeDataHandle;
 10 import com.okhttp.listener.DisposeDownloadListener;
 11 
 12 import android.os.Handler;
 13 import android.os.Looper;
 14 import android.os.Message;
 15 import okhttp3.Call;
 16 import okhttp3.Callback;
 17 import okhttp3.Response;
 18 
 19 /**********************************************************
 20  * @文件名稱:CommonFileCallback.java 23  * @文件描述:專門處理文件下載回調
 24  * @修改歷史:2016年1月23日建立初始版本
 25  **********************************************************/
 26 public class CommonFileCallback implements Callback {
 27     /**
 28      * the java layer exception, do not same to the logic error
 29      */
 30     protected final int NETWORK_ERROR = -1; // the network relative error
 31     protected final int IO_ERROR = -2; // the JSON relative error
 32     protected final String EMPTY_MSG = "";
 33     /**
 34      * 將其它線程的數據轉發到UI線程
 35      */
 36     private static final int PROGRESS_MESSAGE = 0x01;
 37     private Handler mDeliveryHandler;
 38     private DisposeDownloadListener mListener;
 39     private String mFilePath;
 40     private int mProgress;
 41 
 42     public CommonFileCallback(DisposeDataHandle handle) {
 43         this.mListener = (DisposeDownloadListener) handle.mListener;
 44         this.mFilePath = handle.mSource;
 45         this.mDeliveryHandler = new Handler(Looper.getMainLooper()) {
 46             @Override
 47             public void handleMessage(Message msg) {
 48                 switch (msg.what) {
 49                 case PROGRESS_MESSAGE:
 50                     mListener.onProgress((int) msg.obj);
 51                     break;
 52                 }
 53             }
 54         };
 55     }
 56 
 57     @Override
 58     public void onFailure(final Call call, final IOException ioexception) {
 59         mDeliveryHandler.post(new Runnable() {
 60             @Override
 61             public void run() {
 62                 mListener.onFailure(new OkHttpException(NETWORK_ERROR, ioexception));
 63             }
 64         });
 65     }
 66 
 67     @Override
 68     public void onResponse(Call call, Response response) throws IOException {
 69         final File file = handleResponse(response);
 70         mDeliveryHandler.post(new Runnable() {
 71             @Override
 72             public void run() {
 73                 if (file != null) {
 74                     mListener.onSuccess(file);
 75                 } else {
 76                     mListener.onFailure(new OkHttpException(IO_ERROR, EMPTY_MSG));
 77                 }
 78             }
 79         });
 80     }
 81 
 82     /**
 83      * 此時還在子線程中,不則調用回調接口
 84      * 
 85      * @param response
 86      * @return
 87      */
 88     private File handleResponse(Response response) {
 89         if (response == null) {
 90             return null;
 91         }
 92 
 93         InputStream inputStream = null;
 94         File file = null;
 95         FileOutputStream fos = null;
 96         byte[] buffer = new byte[2048];
 97         int length = -1;
 98         int currentLength = 0;
 99         double sumLength = 0;
100         try {
101             file = new File(mFilePath);
102             fos = new FileOutputStream(file);
103             inputStream = response.body().byteStream();
104             sumLength = (double) response.body().contentLength();
105 
106             while ((length = inputStream.read(buffer)) != -1) {
107                 fos.write(buffer, 0, length);
108                 currentLength += length;
109                 mProgress = (int) (currentLength / sumLength * 100);
110                 mDeliveryHandler.obtainMessage(PROGRESS_MESSAGE, mProgress).sendToTarget();
111             }
112             fos.flush();
113         } catch (Exception e) {
114             file = null;
115         } finally {
116             try {
117                 fos.close();
118                 inputStream.close();
119             } catch (IOException e) {
120                 e.printStackTrace();
121             }
122         }
123         return file;
124     }
125 }

 

【client的封裝】對整個流程的調用

  1 package com.okhttp;
  2 
  3 import java.io.InputStream;
  4 import java.util.concurrent.TimeUnit;
  5 
  6 import javax.net.ssl.HostnameVerifier;
  7 import javax.net.ssl.SSLSession;
  8 
  9 import okhttp3.Call;
 10 import okhttp3.OkHttpClient;
 11 import okhttp3.Request;
 12 
 13 import com.okhttp.cookie.SimpleCookieJar;
 14 import com.okhttp.listener.DisposeDataHandle;
 15 import com.okhttp.response.CommonFileCallback;
 16 import com.okhttp.response.CommonJsonCallback;
 17 import com.okhttp.ssl.HttpsUtils;
 18 
 19 /**
 20  * @author vision
 21  * @function 用來發送get,post請求的工具類,包括設置一些請求的共用參數,超時、https的認證等等;
 22  */
 23 public class CommonOkHttpClient
 24 {
 25     private static final int TIME_OUT = 30;
 26     private static OkHttpClient mOkHttpClient;
 27     // private static CommonOkHttpClient mClient = null;
 28 
 29     static
 30     {
 31 
 32         OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
 33         //完成對https的認證;
 34         okHttpClientBuilder.hostnameVerifier(new HostnameVerifier()
 35         {
 36             @Override
 37             public boolean verify(String hostname, SSLSession session)
 38             {
 39                 return true;
 40             }
 41         });
 42 
 43         okHttpClientBuilder.cookieJar(new SimpleCookieJar());
 44         okHttpClientBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
 45         okHttpClientBuilder.readTimeout(TIME_OUT, TimeUnit.SECONDS);
 46         okHttpClientBuilder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);
 47         okHttpClientBuilder.followRedirects(true);//容許被重定向;
 48         /**
 49          * trust all the https point
 50          */
 51         okHttpClientBuilder.sslSocketFactory(HttpsUtils.getSslSocketFactory());
 52         mOkHttpClient = okHttpClientBuilder.build();
 53     }
 54 
 55     /**
 56      * 指定cilent信任指定證書
 57      * 
 58      * @param certificates
 59      */
 60     public static void setCertificates(InputStream... certificates)
 61     {
 62         mOkHttpClient.newBuilder().sslSocketFactory(HttpsUtils.getSslSocketFactory(certificates, null, null)).build();
 63     }
 64 
 65     /**
 66      * 指定client信任全部證書
 67      */
 68     public static void setCertificates()
 69     {
 70         mOkHttpClient.newBuilder().sslSocketFactory(HttpsUtils.getSslSocketFactory());
 71     }
 72 
 73     /**
 74      * 經過構造好的Request,Callback去發送請求
 75      * 
 76      * @param request
 77      * @param callback
 78      */
 79     /*get請求*/
 80     public static Call get(Request request, DisposeDataHandle handle)
 81     {
 82         Call call = mOkHttpClient.newCall(request);
 83         call.enqueue(new CommonJsonCallback(handle));
 84         return call;
 85     }
 86     /*post請求*/
 87     public static Call post(Request request, DisposeDataHandle handle)
 88     {
 89         Call call = mOkHttpClient.newCall(request);
 90         call.enqueue(new CommonJsonCallback(handle));
 91         return call;
 92     }
 93     /*文件下載*/
 94     public static Call downloadFile(Request request, DisposeDataHandle handle)
 95     {
 96         Call call = mOkHttpClient.newCall(request);
 97         call.enqueue(new CommonFileCallback(handle));
 98         return call;
 99     }
100 }

5.測試

【get請求的調用】

【post請求的調用】

【下載文件的請求】

【上傳文件的響應】

【對點擊事件的響應】

 

相關文章
相關標籤/搜索