1. 程式人生 > >android併發網路請求的處理

android併發網路請求的處理

      最近在做android客戶端的統計sdk,為了保證資料統計的準確行,需要把一些基本資訊,和無網路情況下使用者的操作儲存到SqlLite本地資料庫中,等待有網了的時候進行傳;

基本解決思路,離線操作的資料請求URL和請求引數進行封裝,封裝到物件中,轉化為json儲存到SQlLite資料庫中;定時任務檢測網路情況,如果有網,則把資料庫中資料取出,進行網路上傳;

    取出資料庫中請求,就需要處理大量網路請求,同時傳送請求的情況,一般來說一個網路請求都會用使用到一個非同步執行緒,大量的執行緒建立、執行、銷燬又造成了系統資源的浪費,而且同時同時new出多個子執行緒也會造成客戶端卡死現象;於是考慮到能不能做個請求佇列去進行控制

在這個模型中,有高中低三個優先順序通道如下:高優先順序--1,中優先順序--3,低優先順序--2 規則: 1.正常情況下各個優先順序使用各自通道(執行緒) 2.高階通道滿載、中、低階通道空置,則高階請求可使用低階通道 構思: UI執行緒將期望的網路請求url和引數通過一個封裝好的Runnable提交給Service處理(當然也可以交給一個Thread處理,本例使用Service),Service接收到請求,判斷優先順序,加入到相應執行緒池中排隊。執行緒池啟動執行緒發起網路請求,最後通過監聽器將結果返回給Service,Service傳送廣播通知UI執行緒,UI執行緒更新相關介面,結束。 廢話說完,上例子: 首先是封裝好的Runnable
  1. public
    class HttpConnRunnable implements Runnable, Parcelable { 
  2.     publicstaticfinalint HIGH_LEVEL = 0
  3.     publicstaticfinalint NORMAL_LEVEL = 1
  4.     publicstaticfinalint LOW_LEVEL = 2
  5.     privateint mPriority = NORMAL_LEVEL;//優先順序,預設為普通
  6.     private String mUrl = ""
  7.     private HttpConnListener mListener;
    //監聽器
  8.     public HttpConnRunnable() { 
  9.         super(); 
  10.     } 
  11.     public HttpConnRunnable(int priority) { 
  12.         super(); 
  13.         mPriority = priority; 
  14.     }    
  15.     @Override
  16.     publicvoid run() { 
  17.         Log.i(Thread.currentThread().getName(), "----Start to connect:" + mUrl + ", priority:" + mPriority + "-----"); 
  18.         try { 
  19.             Thread.sleep(10000); 
  20.             //TODO:進行網路請求相關操作,並通過listener返回結果
  21.             mListener.onSucceed("Connected to " + mUrl + " succeed!"); 
  22.         } 
  23.         catch (InterruptedException e) { 
  24.             e.printStackTrace(); 
  25.         } 
  26.         Log.i(Thread.currentThread().getName(), "----Finish to connect:" + mUrl + ", priority:" + mPriority + "-----"); 
  27.     } 
  28.     publicint getPriority() { 
  29.         return mPriority; 
  30.     } 
  31.     publicvoid setPriority(int priority) { 
  32.         mPriority = priority; 
  33.     } 
  34.     public String getURL() { 
  35.         return mUrl; 
  36.     } 
  37.     publicvoid setURL(String url) { 
  38.         mUrl = url; 
  39.     } 
  40.     publicvoid setHttpConnListener(HttpConnListener listener) { 
  41.         mListener = listener; 
  42.     } 
  43.     //序列化,為了傳遞給Service,如果是使用Thread處理本例,則無需序列化
  44.     publicstaticfinal Parcelable.Creator CREATOR = new Creator() { 
  45.         @Override
  46.         public HttpConnRunnable createFromParcel(Parcel source) { 
  47.             HttpConnRunnable data = null
  48.             Bundle bundle = source.readBundle(); 
  49.             if(bundle != null) { 
  50.                 data = new HttpConnRunnable(bundle.getInt("PRIORITY")); 
  51.                 data.mUrl = bundle.getString("URL"); 
  52.             } 
  53.             return data; 
  54.         } 
  55.         @Override
  56.         public HttpConnRunnable[] newArray(int size) { 
  57.             returnnew HttpConnRunnable[size]; 
  58.         } 
  59.     }; 
  60.     @Override
  61.     publicint describeContents() { 
  62.         return0
  63.     } 
  64.     @Override
  65.     publicvoid writeToParcel(Parcel dest, int flags) { 
  66.         Bundle bundle = new Bundle(); 
  67.         bundle.putInt("PRIORITY", mPriority); 
  68.         bundle.putString("URL", mUrl); 
  69.         dest.writeBundle(bundle); 
  70.     } 
Service的處理:
  1. publicclass HttpConnService extends Service implements HttpConnListener { 
  2.     publicstaticfinal String HTTP_POOL_PARAM_KEYWORD = "HttpPoolParam";           //網路引數傳遞的關鍵字
  3.     privatefinalint HIGH_POOL_SIZE = 1
  4.     privatefinalint NORMAL_POOL_SIZE = 3
  5.     privatefinalint LOW_POOL_SIZE = 2
  6.     // 可重用固定執行緒數的執行緒池
  7.     private ThreadPoolExecutor mHighPool; 
  8.     private ThreadPoolExecutor mNormalPool; 
  9.     private ThreadPoolExecutor mLowPool; 
  10.     @Override
  11.     publicvoid onCreate() { 
  12.         //初始化所有
  13.         mHighPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(HIGH_POOL_SIZE); 
  14.         mNormalPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(NORMAL_POOL_SIZE); 
  15.         mLowPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(LOW_POOL_SIZE); 
  16.         super.onCreate(); 
  17.     } 
  18.     @Override
  19.     publicint onStartCommand(Intent intent, int flags, int startId) { 
  20.         //接受到來自UI執行緒的請求
  21.         //取出Runnable,並加入到相應佇列
  22.         Bundle bundle = intent.getExtras(); 
  23.         HttpConnRunnable httpConnRunnable = bundle.getParcelable(HTTP_POOL_PARAM_KEYWORD); 
  24.         if (httpConnRunnable != null) { 
  25.             httpConnRunnable.setHttpConnListener(HttpConnService.this); 
  26.             int level = httpConnRunnable.getPriority(); 
  27.             switch (level) { 
  28.                 case HttpConnRunnable.HIGH_LEVEL: 
  29.                     //如果高階池滿而低階池未滿交由低階池處理
  30.                     //如果高階池滿而普通池未滿交由普通池處理
  31.                     //如果高階池未滿則交給高階池處理,否則,交由高階池排隊等候
  32.                     if (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) { 
  33.                         mLowPool.execute(httpConnRunnable); 
  34.                     } 
  35.                     elseif (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mNormalPool.getActiveCount() < NORMAL_POOL_SIZE) { 
  36.                         mNormalPool.execute(httpConnRunnable); 
  37.                     } 
  38.                     else { 
  39.                         mHighPool.execute(httpConnRunnable); 
  40.                     } 
  41.                     break
  42.                 case HttpConnRunnable.NORMAL_LEVEL: 
  43.                     //如果普通池滿而低階池未滿交由低階池處理
  44.                     //如果普通池未滿則交給普通池處理,否則,交由普通池排隊等候
  45.                     if (mNormalPool.getActiveCount() == NORMAL_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) { 
  46.                         mLowPool.execute(httpConnRunnable); 
  47.                     } 
  48.                     else { 
  49.                         mNormalPool.execute(httpConnRunnable); 
  50.                     } 
  51.                     break
  52.                 case HttpConnRunnable.LOW_LEVEL: 
  53.                     mLowPool.execute(httpConnRunnable); 
  54.                     break
  55.             } 
  56.         } 
  57.         returnsuper.onStartCommand(intent, flags, startId); 
  58.     } 
  59.     @Override
  60.     publicvoid onDestroy() { 
  61.         mHighPool.shutdownNow(); 
  62.         mNormalPool.shutdownNow(); 
  63.         mLowPool.shutdownNow(); 
  64.         mNormalPool = null
  65.         mLowPool = null
  66.         super.onDestroy(); 
  67.     } 
  68.     @Override
  69.     public IBinder onBind(Intent intent) { 
  70.         returnnull
  71.     } 
  72.     @Override
  73.     publicvoid onSucceed(String result) { 
  74.         Intent intent = new Intent(); 
  75.         intent.setAction("com.ezstudio.connpool.HttpConnReceiver"); 
  76.         // 要傳送的內容
  77.         intent.putExtra("RESULT", result); 
  78.         // 傳送 一個無序廣播
  79.         sendBroadcast(intent); 
  80.     } 
  81.     @Override
  82.     publicvoid onFailed() { 
  83.         // TODO Auto-generated method stub
  84.     } 
Receiver的處理比較簡單: 
  1. publicclass HttpConnReceiver extends BroadcastReceiver { 
  2.     private HttpConnListener mListener; 
  3.     publicvoid setHttpConnListener (HttpConnListener listener) { 
  4.         mListener = listener; 
  5.     } 
  6.     @Override
  7.     publicvoid onReceive(Context context, Intent intent) { 
  8.         String action = intent.getAction(); 
  9.         if (action.equals("com.ezstudio.connpool.HttpConnReceiver")) { 
  10.             String result = intent.getStringExtra("RESULT"); 
  11.             mListener.onSucceed(result); 
  12.         } 
  13.     }