如何獨立開發一個網絡請求框架

(原創出處爲本博客:http://www.cnblogs.com/linguanh/)php

目錄:java

    前言android

  準備工做git

     開發模式github

    開發原則面試

    線程
安全

    高併發服務器

    TCP/UDP網絡

  本類介紹多線程

     開發選擇

    功能列表

    優勢

    拓展

  完整代碼

   用法例子

     

前言:

  已開源到GitHub,但願你們可以和我一塊兒來完善它,該類確定有不少不足的,但整體來講,仍是不錯的。

  爲何要寫這個東西?緣由以下:

  在此以前已經有不少不錯的網絡請求框架廣爲人知了,例如 android-async-http,okHttp等,這類優秀的框架其底層的實現大部分也是基於系統的 線程池 和 httpClient 或 HttpUrlConnection,其中OK是本身解析http協議的,我相信不少開發者在使用這些框架的時候本身是沒有去了解這些東西的。

  做爲一個合格的Android開發者,我以爲必需要會本身使用系統的SDK提供的API來實現功能,並非不建議使用框架,只是建議在可以在獨立地,不依賴百度,徹底斷網的狀況下去使用現有的資源來實現需求功能後,再去使用這些框架,這樣不至於成爲「框架工程師」,並且,在面試的時候,也能信心十足!

  本文不只僅是對Java/Android而言,一樣的建議能夠折射到其餘語言的開發上。

  

準備工做

  1,瞭解並使用一些經常使用的開發模式,例如單例、觀察者、簡單工廠等。要開發框架,使用開發模式的必須的,不管是從代碼解耦或者是內存優化方面上去看都是必不可少,前者有ImageLoader採用了雙從判斷類型的單例模式,包括Android咱們熟悉的事件機制,它是觀察者模式,還有適配器模式。

  2,瞭解並使用一些開發原則,注意哦,這裏是原則哦,例如接口分離,一個大的項目沒幾個接口怎麼行,並且接口可以咱們帶來很大的方便。

  3,瞭解並學會使用線程以及優化,網絡請求類框架,咱們知道Android中是不能在主線程中(又稱UI線程)進行網絡操做的,那麼咱們的框架中必不可少地要使用到子線程,這就須要你掌握線程類知識,例如簡單的 Thread + Runnable + Handler 組合拳,再重量級點的就使用 AsyncTask。

  4,處理好高併發,一個應用中每每要進行多線程操做,而Java虛擬機對於一個線程的內存分配大約在1M左右,具體多少要看它執行的任務而定。看到線程高併發這些字,第一想到的應該是 線程池,因此線程池你須要去了解並學會靈活使用。

  5,瞭解 Tcp/Udp 數據包的結構以及 Post 的方式差異。還記得有不少招聘條件裏面有不少要求要了解 TCP協議的要求不?若是你看到這樣的要求的時候,內心默唸這個要求有什麼用的話,那就證實你還沒真正地去使用過它,這點等下留意下個人代碼註釋。

  6,其餘 (例如一個編譯器....)

 

本類介紹

  仍是不要說框架了,說類吧,哈哈,不要那麼高大上。接着在上面的準備工做中談到的點,下面我來意義對應解釋,它們是怎樣被用到這個 Http工具類裏面的。

  1,在開發模式上,我採用了靜態內部類的單例模式,這樣有兩個好處,一個是保證了類不使用的時候不會想餓漢模式同樣在開始就佔用內存,而是懶漢模式,而靜態內部類則是爲了解決線程安全的問題,它僅會在使用的時候在JVM虛擬機類的加載第五步時初始化,此步驟中的clinit<>是線程安全的,同時又不會由於使用同步關鍵字 synchronized 而致使其餘的問題,同步失敗或耗資源等。 

public static LghHttp getInstance(){
      return LghHttpStatic.singleLghHttp;
}

private static class LghHttpStatic{
      private static LghHttp singleLghHttp = new LghHttp();
}

 

  2,在開發原則上面,採用了接口分離,主要體如今數據處理方面。

    /** 接口分離 */
    private interface LghHttpBaseListenr{
        void onFailed(int type);
//        void onUrlFailed();
//        void onTimeOut();
//        void onProtocolFailed();
//        void onEncodingFailed();
//        void onIoFailed();
    }

    /** 全局有 requestCode 區分 */
    public interface LghHttpGlobleListener extends LghHttpBaseListenr{
        void onSuccess(int requestCode,String response);
    }

    /** 單一的沒 requestCode 區分 */
    public interface LghHttpSingleListener extends LghHttpBaseListenr{
        void onSuccess(String response);
    }

 

  3,線程和併發方面,採用了newFixdThreadPool 類型的線程池,若是要考慮替換,建議換爲 newCacheThreadPool,他們兩個之間 newFixdThreadPool 能夠控制併發數量,且在整個APP運行過程當中有幾個常駐線程在,避免使用時反覆地new,退出時再銷燬,而 newCacheThreadPool 則會在任務完成後,自動回收線程,它會幫你釋放線程內存,也就不會有常駐線程。

 1 /** 初始化函數 */
 2     public synchronized void init(){
 3         this.threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
 4         this.handler = new Handler(){
 5             @Override
 6             public void handleMessage(Message msg) {
 7                 super.handleMessage(msg);
 8 
 9                 HttpDataBean bean = (HttpDataBean) msg.obj;
10                 LghHttpBaseListenr tempListener;
11                 if(GloblelghHttpListeners!=null){ /** 以全局的優先 */
12                     tempListener = GloblelghHttpListeners;
13                 }else if(bean.getListeners()!=null){
14                     tempListener = bean.getListeners();
15                 }else{
16                     return;
17                 }
18                 switch (msg.what){
19                     case Success:
20                         if(GloblelghHttpListeners!=null){ /** 以全局的優先 */
21                             GloblelghHttpListeners.onSuccess(msg.arg1,bean.getResponse());
22                         }else{
23                             bean.getListeners().onSuccess(bean.getResponse());
24                         }
25                         break;
26                     case UrlFailed:
27                         tempListener.onFailed(UrlFailed);
28                         break;
29                     case TimeOut:
30                         tempListener.onFailed(TimeOut);
31                         break;
32                     case ProtocolFailed:
33                         tempListener.onFailed(ProtocolFailed);
34                         break;
35                     case EncodingFailed:
36                         tempListener.onFailed(EncodingFailed);
37                         break;
38                     case IOFailed:
39                         tempListener.onFailed(IOFailed);
40                         break;
41                     default:
42                         /** 這裏不可能會進入,也看成一個留給你本身的接口吧 */
43                         break;
44                 }
45             }
46         };
47     }
View Code

  4,功能方面,提供了三種常見操做:

    1)Get 請求操做    

 1     /** Get 請求整合 */
 2     public void doGet(final String url){
 3         doGet(-1, url, null);
 4     }
 5 
 6     public void doGet(final int requestCode,final String url){
 7         doGet(requestCode, url, null);
 8     }
 9 
10     public void doGet(
11             final int requestCode,
12             final String url,
13             final LghHttpSingleListener lghHttpListeners)
14     {
15         Runnable runnable = new Runnable() {
16             @Override
17             public void run() {
18                 get(requestCode, url, lghHttpListeners);
19             }
20         };
21         if(threadPool != null){
22             threadPool.execute(runnable);
23         }else{
24             Log.d(TAG,"do get threadPool is null");
25         }
26     }
27 
28     private void get(int requestCode,String url,LghHttpSingleListener lghHttpListener){
29         try {
30             HttpURLConnection httpURLConnection = getHttpUrlConnection(url,"GET");
31             httpURLConnection.setUseCaches(false);
32             sendMessage(Success,requestCode, commonGetResult(httpURLConnection,lghHttpListener));
33         } catch (MalformedURLException e) {
34             dealWithException(e,lghHttpListener);
35         } catch (IOException e) {
36             dealWithException(e,lghHttpListener);
37         }
38     }
View Code

    2)Post 請求操做

 1 /** Post 請求整合 */
 2     public void doPost(String url){
 3         doPost(-1, url);
 4     }
 5 
 6     public void doPost(int requestCode,String url){
 7         doPost(requestCode, url, null, null);
 8     }
 9 
10     public void doPost(int requestCode,String url,LghHttpSingleListener listener){
11         doPost(requestCode, url, null, null,listener);
12     }
13 
14     public void doPost(int requestCode,String url,String[] keys,String[] values){
15         doPost(requestCode, url, keys, values, null);
16     }
17 
18     public void doPost(
19             final int requestCode,
20             final String url,
21             final String[] keys,
22             final String[] values,
23             final LghHttpSingleListener listener
24     ){
25         Runnable runnable = new Runnable() {
26             @Override
27             public void run() {
28                 post(requestCode, url,keys,values, listener);
29             }
30         };
31         if(threadPool != null){
32             threadPool.execute(runnable);
33         }else{
34             Log.d(TAG,"do post threadPool is null");
35         }
36     }
37 
38     /** 採用第一種post協議,application/x-www-form-urlencoded */
39     private void post(
40             int requestCode,
41             String url,
42             String[] keys,
43             String[] values,
44             LghHttpSingleListener listener
45     ){
46         if(url==null){
47             return;
48         }
49         try{
50             HttpURLConnection httpURLConnection = getHttpUrlConnection(url,"POST");
51             httpURLConnection.setDoOutput(true); /** post 必不可少 */
52             httpURLConnection.setUseCaches(false);
53 
54             if(keys!=null && values!=null){
55                 OutputStream outputStream = httpURLConnection.getOutputStream();
56                 commonCombinePostText(keys,values,outputStream);
57                 outputStream.flush();
58                 outputStream.close();
59             }
60             sendMessage(Success,requestCode, commonGetResult(httpURLConnection,listener));
61         }catch (MalformedURLException e){
62             dealWithException(e,listener);
63         } catch (SocketTimeoutException e){
64             dealWithException(e,listener);
65         } catch (ProtocolException e) {
66             dealWithException(e,listener);
67         } catch (UnsupportedEncodingException e) {
68             dealWithException(e,listener);
69         } catch (IOException e) {
70             dealWithException(e,listener);
71         }
72     }
View Code

    3)上傳圖片操做,Tcp 數據包的一些知識,在這裏有用到。

  1 /** 上傳圖片部分整合 */
  2     public void doUpLoadPic(
  3             String url,
  4             String picName,
  5             String streamName,
  6             Bitmap bit
  7     ){
  8         doUpLoadPic(-1, url, null, null, picName, streamName, bit, null);
  9     }
 10 
 11     public void doUpLoadPic(
 12             int requestCode,
 13             String url,
 14             String picName,
 15             String streamName,
 16             Bitmap bit
 17     ){
 18         doUpLoadPic(requestCode, url, null, null, picName, streamName, bit, null);
 19     }
 20 
 21     public void doUpLoadPic(
 22             int requestCode,
 23             String url,
 24             String picName,
 25             String streamName,
 26             Bitmap bit,
 27             LghHttpSingleListener listener
 28     ){
 29         doUpLoadPic(requestCode, url, null, null, picName, streamName, bit, listener);
 30     }
 31 
 32     public void doUpLoadPic(
 33             int requestCode,
 34             String url,
 35             String[] keys,
 36             String[] values,
 37             String picName,
 38             String streamName,
 39             Bitmap bit
 40     ){
 41         doUpLoadPic(requestCode, url, keys, values, picName, streamName, bit, null);
 42     }
 43 
 44     public void doUpLoadPic(
 45             final int requestCode,
 46             final String url,
 47             final String[] keys,
 48             final String[] values,
 49             final String picName,
 50             final String streamName,
 51             final Bitmap bit,
 52             final LghHttpSingleListener listener
 53     ){
 54         Runnable runnable = new Runnable() {
 55             @Override
 56             public void run() {
 57                 UpLoadPic(requestCode, url, keys, values, picName, streamName, bit, listener);
 58             }
 59         };
 60         if(threadPool != null){
 61             threadPool.execute(runnable);
 62         }else{
 63             Log.d(TAG,"do post threadPool is null");
 64         }
 65     }
 66 
 67     /**
 68      * 此函數用來上傳圖片
 69      * post 的 兩種數據包格式:
 70      * 1,application/x-www-form-urlencoded;用來上傳文字
 71      * 2,multipart/form-data; 二進制傳輸,除了文字以外,還能夠用來傳輸 文件,例如圖片!
 72      * 3,multipart/form-data; 必需要帶有分隔符 boundary
 73      * 4,在http post請求的結尾,須要有一個分界線,可是是先後都有--的:--分隔符--
 74      * 參數:
 75      *      url
 76      *      picName    圖片的名稱
 77      *      streamName 流體值的名稱
 78      *      例如採用 php 接收,那麼在服務器獲取圖片名稱的寫法是:$_FILES['streamName']['picName']
 79      **/
 80     private void UpLoadPic(
 81             int requestCode,
 82             String url,
 83             String[] keys,
 84             String[] values,
 85             String picName,
 86             String streamName,
 87             Bitmap bit,
 88             LghHttpSingleListener listener
 89     ){
 90         String twoHyphens = "--";   /** 必定要是 2行 */
 91         String boundary = "******"; /** 數據包分割線能夠自定義 */
 92         try{
 93             HttpURLConnection httpURLConnection = getHttpUrlConnection(url,"POST");
 94             httpURLConnection.setUseCaches(false);
 95             httpURLConnection.setDoOutput(true);
 96             httpURLConnection.setChunkedStreamingMode(1024 * 256); /** 一次傳輸的塊大小 */
 97             /** 數據 --------包頭-------- 格式組裝 */
 98             httpURLConnection.setRequestProperty("Connection","Keep-Alive");
 99             httpURLConnection.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);
100             /** 數據 --------包體-------- 格式組裝*/
101             DataOutputStream body = new DataOutputStream(httpURLConnection.getOutputStream());
102             /** \r\n 是換行 */
103             body.writeBytes(twoHyphens+boundary+"\r\n"); /** 先寫分隔符,標誌和上面的頭分開 */
104             body.writeBytes(
105                     "Content-Disposition:form-data;" +
106                             "name=\"" + streamName + "\";" +
107                             "filename=\"" + picName + "\"" + "\r\n"
108             );
109             /** 寫文本數據體 */
110             body.writeBytes("\r\n");
111             if(keys!=null && values!=null){
112                 body.writeBytes(twoHyphens+boundary+"\r\n");
113                 body.writeBytes("Content-Disposition:form-data;");
114                 commonCombinePostText(keys,values,body);
115                 body.writeBytes("\r\n");
116             }
117             /** -------下面開始寫圖片二進制------- */
118             /** 下面是先壓縮 */
119             int compress = 100;
120             ByteArrayOutputStream baos = new ByteArrayOutputStream();
121             bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
122             if(IsOpenCompress){
123                 while (baos.toByteArray().length / 1024 > CompressLimit) {
124                     baos.reset();
125                     compress -= 10;
126                     if(compress==0){
127                         bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
128                         break;
129                     }
130                     bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
131                 }
132             }
133             /** 開始寫 */
134             InputStream picStream = new ByteArrayInputStream(baos.toByteArray());
135             byte[] buffer = new byte[10*1024];
136             int count;
137             while((count = picStream.read(buffer))!=-1){
138                 body.write(buffer,0,count);
139             }
140             picStream.close();
141             body.writeBytes("\r\n");
142             body.writeBytes(twoHyphens + boundary + twoHyphens +"\r\n");
143             body.flush();
144             /** 寫完 */
145             sendMessage(Success,requestCode,commonGetResult(httpURLConnection,listener));
146             body.close();
147         }catch (MalformedURLException e){
148             dealWithException(e,listener);
149         } catch (SocketTimeoutException e){
150             dealWithException(e,listener);
151         } catch (ProtocolException e) {
152             dealWithException(e,listener);
153         } catch (UnsupportedEncodingException e) {
154             dealWithException(e,listener);
155         } catch (IOException e) {
156             dealWithException(e,listener);
157         }
158     }
View Code

 

  5,優勢:

    1)絕對的輕量級,能夠提高APK 的體積優化,沒依賴其餘第三方庫

    2)內存管理方面能夠放心

    3)請求速度方面是純系統的 HttpUrlConnection,沒有過多的代碼片斷

  6,能夠進一步解耦拆分類,爲了方便我本身使用因此我寫在了一個裏面,能夠分爲:

    1)公共部分

 1     /** 公共部分,異常集合處理 */
 2     private void dealWithException(
 3             Exception e,
 4             LghHttpSingleListener lghHttpListeners)
 5     {
 6         HttpDataBean bean = new HttpDataBean();
 7         bean.setListeners(lghHttpListeners);
 8         if(e instanceof MalformedURLException){
 9             Log.d(TAG, "連接格式有問題 "+e.toString());
10             sendMessage(UrlFailed,bean);
11         }else if(e instanceof SocketTimeoutException){
12             Log.d(TAG, "鏈接超時 "+e.toString());
13             sendMessage(TimeOut,bean);
14         }else if(e instanceof ProtocolException){
15             Log.d(TAG, "協議異常,注意不要屢次鏈接 " + e.toString());
16             sendMessage(ProtocolFailed, bean);
17         }else if(e instanceof UnsupportedEncodingException){
18             Log.d(TAG, "編碼類型異常 " + e.toString());
19             sendMessage(EncodingFailed, bean);
20         }else if(e instanceof IOException){
21             Log.d(TAG, "io 異常 " + e.toString());
22             sendMessage(IOFailed,bean);
23         }
24     }
25 
26     /** 獲取一個HttpUrlConnection,合併一些公共部分 */
27     private static HttpURLConnection getHttpUrlConnection
28             (String url,String requestWay) throws IOException {
29         Log.d(TAG,"url is "+url);
30         URL mRrl = new URL(url);
31         HttpURLConnection httpURLConnection = (HttpURLConnection) mRrl.openConnection();
32         httpURLConnection.setRequestMethod(requestWay);
33         httpURLConnection.setRequestProperty("Charset", "UTF-8");
34         httpURLConnection.setConnectTimeout(5 * 1000);
35         return httpURLConnection;
36     }
37 
38     /** 獲取結果公共部分 */
39     private HttpDataBean commonGetResult(
40             HttpURLConnection httpURLConnection,
41             LghHttpSingleListener listener
42     ) throws IOException {
43         if(httpURLConnection==null){
44             return null;
45         }
46         BufferedReader br = new BufferedReader
47                 (
48                         new InputStreamReader(httpURLConnection.getInputStream(),"UTF-8"),
49                         8*1024
50                 );
51         StringBuffer resultBuffer = new StringBuffer("");
52         String line;
53         while ((line = br.readLine())!=null){
54             resultBuffer.append(line);
55         }
56         HttpDataBean bean = new HttpDataBean();
57         bean.setResponse(resultBuffer.toString());
58         bean.setListeners(listener);
59         br.close();
60         return bean;
61     }
62 
63     /** 組合 post 文本數據公共部分 */
64     private OutputStream commonCombinePostText(
65             String[] keys,
66             String[] values,
67             OutputStream outputStream) throws IOException
68     {
69         StringBuffer requestStr = new StringBuffer();
70         int keysLength = keys.length;
71         for(int i=0;i<keysLength;i++){
72             requestStr.append(keys[i]+"="+values[i]+"&");
73         }
74         outputStream.write(requestStr.toString().getBytes());
75         return outputStream;
76     }
View Code

    2)數據部分

 1 /**
 2      * LghHttp 基礎數據類
 3      * 做爲 handler 傳遞的數據種子,只在成功時傳遞
 4      * */
 5     private class HttpDataBean implements Serializable{
 6 
 7         private String response;
 8         private LghHttpSingleListener listeners;
 9 
10         public void setResponse(String response){
11             this.response = response;
12         }
13 
14         public void setListeners(LghHttpSingleListener listeners){
15             this.listeners = listeners;
16         }
17 
18         public String getResponse(){
19             return this.response;
20         }
21 
22         public LghHttpSingleListener getListeners(){
23             return this.listeners;
24         }
25     }
View Code

    3)請求核心部分

  7,拓展,加入視頻上傳部分。

 

完整代碼:

  上面嵌套講解拆分了,這裏提供完整的。

 

  1 package com.lghsaleimage;
  2 
  3 import android.graphics.Bitmap;
  4 import android.os.Handler;
  5 import android.os.Message;
  6 import android.util.Log;
  7 
  8 import java.io.BufferedReader;
  9 import java.io.ByteArrayInputStream;
 10 import java.io.ByteArrayOutputStream;
 11 import java.io.DataOutputStream;
 12 import java.io.IOException;
 13 import java.io.InputStream;
 14 import java.io.InputStreamReader;
 15 import java.io.OutputStream;
 16 import java.io.Serializable;
 17 import java.io.UnsupportedEncodingException;
 18 import java.net.HttpURLConnection;
 19 import java.net.MalformedURLException;
 20 import java.net.ProtocolException;
 21 import java.net.SocketTimeoutException;
 22 import java.net.URL;
 23 import java.util.concurrent.Executors;
 24 import java.util.concurrent.ThreadPoolExecutor;
 25 
 26 /**
 27  * Created by 林冠宏(指尖下的幽靈) on 2016/8/11.
 28  *
 29  * Blog : http://www.cnblogs.com/linguanh/;
 30  *
 31  * Name : http 工具類
 32  *
 33  * 前言:
 34  *     但願你們可以和我一塊兒來完善它,該類確定有不少不足的,但整體來講,仍是不錯的。
 35  *
 36  * 下面是簡介和拓展:
 37  *
 38  *     1, 考慮到網絡請求必不可少,採用了靜態內部類單例模式
 39  *
 40  *     2, 採用 newFixedThreadPool 線程池來管理併發線程,
 41  *        若是要替換,建議使用 newCacheThreadPool
 42  *
 43  *     3, 功能方面提供三種常見操做:
 44  *           1)Get請求
 45  *           2)Post請求
 46  *           3)圖片上傳
 47  *     4, 優勢:
 48  *           1) 絕對的輕量級,能夠提高 APK 體積優化
 49  *           2)內存管理方面能夠放心
 50  *           3)請求速度方法是純系統的 HttpUrlConnection 請求,
 51  *              沒有過多的代碼片斷
 52  *
 53  *     5,能夠進一步解耦拆分類,分爲:
 54  *           1)公共部分
 55  *           2)數據部分
 56  *           3)請求核心部分
 57  *
 58  *     6, 加入視頻上傳部分
 59  *
 60  */
 61 
 62 public class LghHttp {
 63 
 64     private final static String TAG = "zzzzz";
 65 
 66     public final static int Success = 0x10;
 67     public final static int UrlFailed = 0x11;
 68     public final static int TimeOut = 0x12;
 69     public final static int ProtocolFailed = 0x13;
 70     public final static int EncodingFailed = 0x14;
 71     public final static int IOFailed = 0x15;
 72 
 73     private final static boolean IsOpenCompress = true;/** 是否開啓壓縮 */
 74     private final static int CompressLimit = 500;      /** 壓縮級別,單位是 K */
 75 
 76     private ThreadPoolExecutor threadPool;
 77     private Handler handler;
 78     /**
 79      * 全局回調接口 GloblelghHttpListeners
 80      * 注意:
 81      *     我的建議,若是請求頁面多的,那就不要使用全局接口。儘可能採用singleInterface
 82      *     不然,你須要在用戶層頁面的每次onResume從新設置
 83      * */
 84     private LghHttpGlobleListener GloblelghHttpListeners;
 85 
 86     public static LghHttp getInstance(){
 87         return LghHttpStatic.singleLghHttp;
 88     }
 89 
 90     private static class LghHttpStatic{
 91         private static LghHttp singleLghHttp = new LghHttp();
 92     }
 93 
 94     /** 銷燬,內存釋放善後操做 */
 95     public void destroy(){
 96         if(threadPool!=null){
 97             if(!threadPool.isShutdown()){
 98                 threadPool.shutdown();
 99                 threadPool = null;
100             }
101         }
102         if(handler!=null){
103             handler.removeCallbacksAndMessages(null);
104             handler = null;
105         }
106         if(GloblelghHttpListeners!=null){
107             GloblelghHttpListeners = null;
108         }
109         LghHttpStatic.singleLghHttp = null;
110     }
111 
112     public void setGloblelghHttpListeners(LghHttpGlobleListener GloblelghHttpListeners){
113         this.GloblelghHttpListeners = GloblelghHttpListeners;
114     }
115 
116     /**
117      * LghHttp 基礎數據類
118      * 做爲 handler 傳遞的數據種子,只在成功時傳遞
119      * */
120     private class HttpDataBean implements Serializable{
121 
122         private String response;
123         private LghHttpSingleListener listeners;
124 
125         public void setResponse(String response){
126             this.response = response;
127         }
128 
129         public void setListeners(LghHttpSingleListener listeners){
130             this.listeners = listeners;
131         }
132 
133         public String getResponse(){
134             return this.response;
135         }
136 
137         public LghHttpSingleListener getListeners(){
138             return this.listeners;
139         }
140     }
141 
142     /** 初始化函數 */
143     public synchronized void init(){
144         this.threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
145         this.handler = new Handler(){
146             @Override
147             public void handleMessage(Message msg) {
148                 super.handleMessage(msg);
149 
150                 HttpDataBean bean = (HttpDataBean) msg.obj;
151                 LghHttpBaseListenr tempListener;
152                 if(GloblelghHttpListeners!=null){ /** 以全局的優先 */
153                     tempListener = GloblelghHttpListeners;
154                 }else if(bean.getListeners()!=null){
155                     tempListener = bean.getListeners();
156                 }else{
157                     return;
158                 }
159                 switch (msg.what){
160                     case Success:
161                         if(GloblelghHttpListeners!=null){ /** 以全局的優先 */
162                             GloblelghHttpListeners.onSuccess(msg.arg1,bean.getResponse());
163                         }else{
164                             bean.getListeners().onSuccess(bean.getResponse());
165                         }
166                         break;
167                     case UrlFailed:
168                         tempListener.onFailed(UrlFailed);
169                         break;
170                     case TimeOut:
171                         tempListener.onFailed(TimeOut);
172                         break;
173                     case ProtocolFailed:
174                         tempListener.onFailed(ProtocolFailed);
175                         break;
176                     case EncodingFailed:
177                         tempListener.onFailed(EncodingFailed);
178                         break;
179                     case IOFailed:
180                         tempListener.onFailed(IOFailed);
181                         break;
182                     default:
183                         /** 這裏不可能會進入,也看成一個留給你本身的接口吧 */
184                         break;
185                 }
186             }
187         };
188     }
189 
190     /** handler 發消息部分整合 */
191     private void sendMessage(int what,int code,Object object){
192         Message msg = new Message();
193         msg.what = what;
194         msg.arg1 = code;
195         msg.obj = object;
196         handler.sendMessage(msg);
197     }
198 
199     private void sendMessage(int what,Object object){
200         sendMessage(what, -1, object);
201     }
202 
203     /**
204      * requestCode 請求標識符,方便區分
205      * */
206 
207     /** Get 請求整合 */
208     public void doGet(final String url){
209         doGet(-1, url, null);
210     }
211 
212     public void doGet(final int requestCode,final String url){
213         doGet(requestCode, url, null);
214     }
215 
216     public void doGet(
217             final int requestCode,
218             final String url,
219             final LghHttpSingleListener lghHttpListeners)
220     {
221         Runnable runnable = new Runnable() {
222             @Override
223             public void run() {
224                 get(requestCode, url, lghHttpListeners);
225             }
226         };
227         if(threadPool != null){
228             threadPool.execute(runnable);
229         }else{
230             Log.d(TAG,"do get threadPool is null");
231         }
232     }
233 
234     private void get(int requestCode,String url,LghHttpSingleListener lghHttpListener){
235         try {
236             HttpURLConnection httpURLConnection = getHttpUrlConnection(url,"GET");
237             httpURLConnection.setUseCaches(false);
238             sendMessage(Success,requestCode, commonGetResult(httpURLConnection,lghHttpListener));
239         } catch (MalformedURLException e) {
240             dealWithException(e,lghHttpListener);
241         } catch (IOException e) {
242             dealWithException(e,lghHttpListener);
243         }
244     }
245 
246     /** Post 請求整合 */
247     public void doPost(String url){
248         doPost(-1, url);
249     }
250 
251     public void doPost(int requestCode,String url){
252         doPost(requestCode, url, null, null);
253     }
254 
255     public void doPost(int requestCode,String url,LghHttpSingleListener listener){
256         doPost(requestCode, url, null, null,listener);
257     }
258 
259     public void doPost(int requestCode,String url,String[] keys,String[] values){
260         doPost(requestCode, url, keys, values, null);
261     }
262 
263     public void doPost(
264             final int requestCode,
265             final String url,
266             final String[] keys,
267             final String[] values,
268             final LghHttpSingleListener listener
269     ){
270         Runnable runnable = new Runnable() {
271             @Override
272             public void run() {
273                 post(requestCode, url,keys,values, listener);
274             }
275         };
276         if(threadPool != null){
277             threadPool.execute(runnable);
278         }else{
279             Log.d(TAG,"do post threadPool is null");
280         }
281     }
282 
283     /** 採用第一種post協議,application/x-www-form-urlencoded */
284     private void post(
285             int requestCode,
286             String url,
287             String[] keys,
288             String[] values,
289             LghHttpSingleListener listener
290     ){
291         if(url==null){
292             return;
293         }
294         try{
295             HttpURLConnection httpURLConnection = getHttpUrlConnection(url,"POST");
296             httpURLConnection.setDoOutput(true); /** post 必不可少 */
297             httpURLConnection.setUseCaches(false);
298 
299             if(keys!=null && values!=null){
300                 OutputStream outputStream = httpURLConnection.getOutputStream();
301                 commonCombinePostText(keys,values,outputStream);
302                 outputStream.flush();
303                 outputStream.close();
304             }
305             sendMessage(Success,requestCode, commonGetResult(httpURLConnection,listener));
306         }catch (MalformedURLException e){
307             dealWithException(e,listener);
308         } catch (SocketTimeoutException e){
309             dealWithException(e,listener);
310         } catch (ProtocolException e) {
311             dealWithException(e,listener);
312         } catch (UnsupportedEncodingException e) {
313             dealWithException(e,listener);
314         } catch (IOException e) {
315             dealWithException(e,listener);
316         }
317     }
318 
319     /** 上傳圖片部分整合 */
320     public void doUpLoadPic(
321             String url,
322             String picName,
323             String streamName,
324             Bitmap bit
325     ){
326         doUpLoadPic(-1, url, null, null, picName, streamName, bit, null);
327     }
328 
329     public void doUpLoadPic(
330             int requestCode,
331             String url,
332             String picName,
333             String streamName,
334             Bitmap bit
335     ){
336         doUpLoadPic(requestCode, url, null, null, picName, streamName, bit, null);
337     }
338 
339     public void doUpLoadPic(
340             int requestCode,
341             String url,
342             String picName,
343             String streamName,
344             Bitmap bit,
345             LghHttpSingleListener listener
346     ){
347         doUpLoadPic(requestCode, url, null, null, picName, streamName, bit, listener);
348     }
349 
350     public void doUpLoadPic(
351             int requestCode,
352             String url,
353             String[] keys,
354             String[] values,
355             String picName,
356             String streamName,
357             Bitmap bit
358     ){
359         doUpLoadPic(requestCode, url, keys, values, picName, streamName, bit, null);
360     }
361 
362     public void doUpLoadPic(
363             final int requestCode,
364             final String url,
365             final String[] keys,
366             final String[] values,
367             final String picName,
368             final String streamName,
369             final Bitmap bit,
370             final LghHttpSingleListener listener
371     ){
372         Runnable runnable = new Runnable() {
373             @Override
374             public void run() {
375                 UpLoadPic(requestCode, url, keys, values, picName, streamName, bit, listener);
376             }
377         };
378         if(threadPool != null){
379             threadPool.execute(runnable);
380         }else{
381             Log.d(TAG,"do post threadPool is null");
382         }
383     }
384 
385     /**
386      * 此函數用來上傳圖片
387      * post 的 兩種數據包格式:
388      * 1,application/x-www-form-urlencoded;用來上傳文字
389      * 2,multipart/form-data; 二進制傳輸,除了文字以外,還能夠用來傳輸 文件,例如圖片!
390      * 3,multipart/form-data; 必需要帶有分隔符 boundary
391      * 4,在http post請求的結尾,須要有一個分界線,可是是先後都有--的:--分隔符--
392      * 參數:
393      *      url
394      *      picName    圖片的名稱
395      *      streamName 流體值的名稱
396      *      例如採用 php 接收,那麼在服務器獲取圖片名稱的寫法是:$_FILES['streamName']['picName']
397      **/
398     private void UpLoadPic(
399             int requestCode,
400             String url,
401             String[] keys,
402             String[] values,
403             String picName,
404             String streamName,
405             Bitmap bit,
406             LghHttpSingleListener listener
407     ){
408         String twoHyphens = "--";   /** 必定要是 2行 */
409         String boundary = "******"; /** 數據包分割線能夠自定義 */
410         try{
411             HttpURLConnection httpURLConnection = getHttpUrlConnection(url,"POST");
412             httpURLConnection.setUseCaches(false);
413             httpURLConnection.setDoOutput(true);
414             httpURLConnection.setChunkedStreamingMode(1024 * 256); /** 一次傳輸的塊大小 */
415             /** 數據 --------包頭-------- 格式組裝 */
416             httpURLConnection.setRequestProperty("Connection","Keep-Alive");
417             httpURLConnection.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);
418             /** 數據 --------包體-------- 格式組裝*/
419             DataOutputStream body = new DataOutputStream(httpURLConnection.getOutputStream());
420             /** \r\n 是換行 */
421             body.writeBytes(twoHyphens+boundary+"\r\n"); /** 先寫分隔符,標誌和上面的頭分開 */
422             body.writeBytes(
423                     "Content-Disposition:form-data;" +
424                             "name=\"" + streamName + "\";" +
425                             "filename=\"" + picName + "\"" + "\r\n"
426             );
427             /** 寫文本數據體 */
428             body.writeBytes("\r\n");
429             if(keys!=null && values!=null){
430                 body.writeBytes(twoHyphens+boundary+"\r\n");
431                 body.writeBytes("Content-Disposition:form-data;");
432                 commonCombinePostText(keys,values,body);
433                 body.writeBytes("\r\n");
434             }
435             /** -------下面開始寫圖片二進制------- */
436             /** 下面是先壓縮 */
437             int compress = 100;
438             ByteArrayOutputStream baos = new ByteArrayOutputStream();
439             bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
440             if(IsOpenCompress){
441                 while (baos.toByteArray().length / 1024 > CompressLimit) {
442                     baos.reset();
443                     compress -= 10;
444                     if(compress==0){
445                         bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
446                         break;
447                     }
448                     bit.compress(Bitmap.CompressFormat.JPEG, compress, baos);
449                 }
450             }
451             /** 開始寫 */
452             InputStream picStream = new ByteArrayInputStream(baos.toByteArray());
453             byte[] buffer = new byte[10*1024];
454             int count;
455             while((count = picStream.read(buffer))!=-1){
456                 body.write(buffer,0,count);
457             }
458             picStream.close();
459             body.writeBytes("\r\n");
460             body.writeBytes(twoHyphens + boundary + twoHyphens +"\r\n");
461             body.flush();
462             /** 寫完 */
463             sendMessage(Success,requestCode,commonGetResult(httpURLConnection,listener));
464             body.close();
465         }catch (MalformedURLException e){
466             dealWithException(e,listener);
467         } catch (SocketTimeoutException e){
468             dealWithException(e,listener);
469         } catch (ProtocolException e) {
470             dealWithException(e,listener);
471         } catch (UnsupportedEncodingException e) {
472             dealWithException(e,listener);
473         } catch (IOException e) {
474             dealWithException(e,listener);
475         }
476     }
477 
478     /** 公共部分,異常集合處理 */
479     private void dealWithException(
480             Exception e,
481             LghHttpSingleListener lghHttpListeners)
482     {
483         HttpDataBean bean = new HttpDataBean();
484         bean.setListeners(lghHttpListeners);
485         if(e instanceof MalformedURLException){
486             Log.d(TAG, "連接格式有問題 "+e.toString());
487             sendMessage(UrlFailed,bean);
488         }else if(e instanceof SocketTimeoutException){
489             Log.d(TAG, "鏈接超時 "+e.toString());
490             sendMessage(TimeOut,bean);
491         }else if(e instanceof ProtocolException){
492             Log.d(TAG, "協議異常,注意不要屢次鏈接 " + e.toString());
493             sendMessage(ProtocolFailed, bean);
494         }else if(e instanceof UnsupportedEncodingException){
495             Log.d(TAG, "編碼類型異常 " + e.toString());
496             sendMessage(EncodingFailed, bean);
497         }else if(e instanceof IOException){
498             Log.d(TAG, "io 異常 " + e.toString());
499             sendMessage(IOFailed,bean);
500         }
501     }
502 
503     /** 獲取一個HttpUrlConnection,合併一些公共部分 */
504     private static HttpURLConnection getHttpUrlConnection
505             (String url,String requestWay) throws IOException {
506         Log.d(TAG,"url is "+url);
507         URL mRrl = new URL(url);
508         HttpURLConnection httpURLConnection = (HttpURLConnection) mRrl.openConnection();
509         httpURLConnection.setRequestMethod(requestWay);
510         httpURLConnection.setRequestProperty("Charset", "UTF-8");
511         httpURLConnection.setConnectTimeout(5 * 1000);
512         return httpURLConnection;
513     }
514 
515     /** 獲取結果公共部分 */
516     private HttpDataBean commonGetResult(
517             HttpURLConnection httpURLConnection,
518             LghHttpSingleListener listener
519     ) throws IOException {
520         if(httpURLConnection==null){
521             return null;
522         }
523         BufferedReader br = new BufferedReader
524                 (
525                         new InputStreamReader(httpURLConnection.getInputStream(),"UTF-8"),
526                         8*1024
527                 );
528         StringBuffer resultBuffer = new StringBuffer("");
529         String line;
530         while ((line = br.readLine())!=null){
531             resultBuffer.append(line);
532         }
533         HttpDataBean bean = new HttpDataBean();
534         bean.setResponse(resultBuffer.toString());
535         bean.setListeners(listener);
536         br.close();
537         return bean;
538     }
539 
540     /** 組合 post 文本數據公共部分 */
541     private OutputStream commonCombinePostText(
542             String[] keys,
543             String[] values,
544             OutputStream outputStream) throws IOException
545     {
546         StringBuffer requestStr = new StringBuffer();
547         int keysLength = keys.length;
548         for(int i=0;i<keysLength;i++){
549             requestStr.append(keys[i]+"="+values[i]+"&");
550         }
551         outputStream.write(requestStr.toString().getBytes());
552         return outputStream;
553     }
554 
555     /** 接口分離 */
556     private interface LghHttpBaseListenr{
557         void onFailed(int type);
558 //        void onUrlFailed();
559 //        void onTimeOut();
560 //        void onProtocolFailed();
561 //        void onEncodingFailed();
562 //        void onIoFailed();
563     }
564 
565     /** 全局有 requestCode 區分 */
566     public interface LghHttpGlobleListener extends LghHttpBaseListenr{
567         void onSuccess(int requestCode,String response);
568     }
569 
570     /** 單一的沒 requestCode 區分 */
571     public interface LghHttpSingleListener extends LghHttpBaseListenr{
572         void onSuccess(String response);
573     }
574 
575 }

 

 

用法例子

  1 package lgh.httpdemo;
  2 
  3 import android.graphics.BitmapFactory;
  4 import android.os.Bundle;
  5 import android.support.v7.app.AppCompatActivity;
  6 import android.util.Log;
  7 import android.widget.Toast;
  8 
  9 public class MainActivity extends AppCompatActivity {
 10 
 11     private LghHttp lghHttp = LghHttp.getInstance();
 12 
 13     @Override
 14     protected void onCreate(Bundle savedInstanceState) {
 15         super.onCreate(savedInstanceState);
 16         setContentView(R.layout.activity_main);
 17 
 18         /** Example 1 */
 19         /** 使用全局接口併發起 post 操做 */
 20         lghHttp.setGloblelghHttpListeners(new LghHttp.LghHttpGlobleListener() {
 21             @Override
 22             public void onFailed(int type) {
 23                 switch (type) {
 24                     case LghHttp.UrlFailed:
 25 
 26                         break;
 27                     case LghHttp.Success:
 28 
 29                         break;
 30                     case LghHttp.TimeOut:
 31 
 32                         break;
 33                     /**  .... */
 34                 }
 35             }
 36 
 37             @Override
 38             public void onSuccess(int requestCode, String response) {
 39                 Log.d("zzzzz", "LghHttpGlobleListener do post response "
 40                         + response + " requestCode is " + requestCode);
 41                 switch (requestCode) {
 42                     case 123:
 43                         /** 對應操做 */
 44                         break;
 45                 }
 46             }
 47 
 48         });
 49         for(int i=0;i<30;i++){
 50             final int j = i;
 51             lghHttp.doPost
 52                     (
 53                             j,
 54                             "http://121.42.190.18/ydnurse/Controller/noteController.php?func=GetNote",
 55                             null
 56                     );
 57         }
 58         // 帶有鍵值
 59         lghHttp.doPost
 60                 (
 61                         145,
 62                         "http://121.42.190.18/ydnurse/Controller/noteController.php?func=GetNote",
 63                         new String[]{"userName","userAge","userSex"},
 64                         new String[]{"林冠宏","21","Box"},
 65                         null
 66                 );
 67         
 68         /** -----測試下面的例子,要把全局的接口 LghHttpGlobleListener 設置爲 NUll----- */
 69         /** Example 2 */
 70         lghHttp.doGet
 71                 (
 72                         123,
 73                         "http://121.42.190.18/ydnurse/Controller/noteController.php?func=GetNote",
 74                         new LghHttp.LghHttpSingleListener() {
 75                             @Override
 76                             public void onSuccess(String response) {
 77 
 78                             }
 79 
 80                             @Override
 81                             public void onFailed(int type) {
 82 
 83                             }
 84                         }
 85                 );
 86         /** UpPic Example 3 */
 87 
 88         lghHttp.doUpLoadPic(
 89                 "http://www.xiangjiaoyun.com:8888/BCapp/BananaCloudServer/userPicUploadFile.php?" +
 90                         "account=13726204215&postid=0&type=2",
 91                 "123.jpg",
 92                 "uploadedfile",
 93                 BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)
 94         );
 95 
 96         lghHttp.doUpLoadPic(
 97                 1456,
 98                 "http://www.xiangjiaoyun.com:8888/BCapp/BananaCloudServer/userPicUploadFile.php?" +
 99                         "account=13726204215&postid=0&type=2",
100                 "123.jpg",
101                 "uploadedfile",
102                 BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher),
103                 new LghHttp.LghHttpSingleListener() {
104                     @Override
105                     public void onSuccess(String response) {
106                         Toast.makeText(MainActivity.this,"上傳圖片成功",Toast.LENGTH_SHORT).show();
107                     }
108 
109                     @Override
110                     public void onFailed(int type) {
111 
112                     }
113                 }
114         );
115     }
116 }
相關文章
相關標籤/搜索