(原創出處爲本博客: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 }
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 }
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 }
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 }
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 }
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 }
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 }