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     /** 公共部分