1. 程式人生 > >如何獨立開發一個網路請求框架

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

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