1. 程式人生 > >自己實現的一個簡單的HttpEngine庫

自己實現的一個簡單的HttpEngine庫

Github託管地址: https://github.com/xiebudong/HttpEngine

因為做的專案是網路視訊相關的, 所以需要把業務無關的邏輯獨立出來, 其中一大塊就是對Server的請求, 其中包括對直播點播列表的請求和對海報的請求, 在外加一些額外的和伺服器同步的請求,  總之歸結起來就只有兩種: ①請求一個字串(一般是基於json通訊) , ②請求檔案(海報或者升級apk)

接下來就可以把對網路的請求獨立出來單獨維護, 這樣不但增加了模組的複用性, 而且降低了程式碼的耦合度。

於是我把網路請求封裝成了一個library,  在專案中使用起來就方便多了。

庫的名稱叫HttpEngine,  其中核心的兩個API是:

requestString(...);

requestFile(...);

這樣業務相關的邏輯可以再對這個模組的使用進行封裝, 一層一層最終使程式碼的層次性非常清晰。

下面詳細記錄這個庫的使用 :

HttpEngine是android平臺的一個簡單的http引擎(簡單、實用),支援併發請求字串和下載檔案, 同時支援斷點續傳下載。

引擎打包為lib工程。在專案中直接以lib工程引用方式使用,也可以直接將生產的jar包放在專案的libs目錄下。

另外,專案還附帶了示例應用 - HttpEngineSample, 可以用從這個示例程式瞭解HttpEngine的使用, 也可以直接看看這個庫的使用效果怎麼樣。

HttpEngineSample的執行效果:


引擎以單例模式使用。

API使用很簡單:

HttpEngine.instance().init();

HttpEngine.instance().uninit();

HttpEngine.instance().needDebug(boolean isNeed);

HttpEngine.instance().requestString(...);

HttpEngine.instance().requestFile(...);

更詳細的API使用說明見 HttpEngine/doc/index.html

要注意幾點: init()和uninit()要成對呼叫, 而且不能漏調, 否則會引發IllegalStateException.

比如請求一個網頁:

void requestString()
    {
          StringRequest req = new StringRequest("http://www.baidu.com");
          HttpEngine.instance().requestString(req, new StringObserver() {

              @Override
            public void done(StringRequest req, StringResponse resp) 
            {
                  // TODO Auto-generated method stub
                  Log.i(LOG_TAG, resp.getRespString());
              }
          });
    }

再比如下載一個檔案並決定是否支援斷點續傳,(並支援下載過程中終止下載, 下次再下載同一個檔案時只要上次下載一半的檔案沒有被手動刪掉,則會從已下載的部分開始斷點續傳下載):

void downloadFile(int id, boolean isBreakpoint, String downloadUrl, String fileSavePath)
{
	Log.i(LOG_TAG, "downloadFile id: " + id);
	FileRequest req = null;
	if (isBreakpoint)
	{
		req = new FileRequest(downloadUrl,  fileSavePath);
		req.setIsSupportBreakpointResume(true); // 顯示設定支援斷點續傳。
	}
	else
	{
		// 預設不支援斷點續傳, 無論上次有沒有下完,第二次下載時會刪除之前下載的檔案。
		req = new FileRequest(downloadUrl,  fileSavePath);
	}
	req.setId(id);
	Controller controller = HttpEngine.instance().requestFile(req, new FileObserver() {
		
		@Override
		public void done(FileRequest req, FileResponse resp) {
			// TODO Auto-generated method stub				
//				Log.i(LOG_TAG, req.toString());
//				Log.i(LOG_TAG, resp.toString());
			
			if (resp.getResponseState() != State.OK)
			{
				Log.w(LOG_TAG, "req " + req.getId() + " failed");
			}
			
			runOnUiThread(new UiUpdater(req.getId(), resp.getDownloadPercent()));
		}
	});
	if (controller == null)
	{
		Log.w(LOG_TAG, "request failed , check your network, or filter HttpEngine log for more detail info.");
	}
	else
	{
		mControllerMap.put(id, controller);  // controller儲存起來以便後面可以終止下載, 比如正在下載時
	}
}

以上無論是請求字串還是請求檔案都是非同步併發執行的。 所以函式的執行都不會阻塞主執行緒, 注意如果同時發出的請求比較多的話,最好設定請求id,以便在callback中區分是哪個請求的響應。

另外, 可以通過呼叫 HttpEngine.instance().needDebug(boolean isNeed); 來決定要不要檢視引擎的log輸出, 如果打開了這個開關, 便可以在logcat過濾HttpEngine來檢視HttpEngine庫的執行log(當請求失敗時,對除錯是非常有幫助的)。
當然,如果請求失敗也可以把callback回傳的stringRequest req, StringResponse resp 或者 FileRequest req, FileResponse resp 打印出來(toString), 來檢視為什麼失敗了。