1. 程式人生 > >android非同步請求asyncTask使用—分析getResponseCode()阻塞

android非同步請求asyncTask使用—分析getResponseCode()阻塞

在實際應用中經常會遇到比較耗時任務的處理,比如網路連線,資料庫操作等情況時,如果這些操作都是放在主執行緒(UI執行緒)中,則會造成UI的假死現象,Android中可以使用AsyncTask和Handler兩種非同步方式來解決這種問題。

AsyncTask(非同步任務處理)

在使用AsyncTask時處理類需要繼承AsyncTask,提供三個泛型引數,並且過載AsyncTask的四個方法(至少過載一個)。

An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called 

ParamsProgress and Result, and 4 steps, called onPreExecutedoInBackgroundonProgressUpdate and onPostExecute.

三個泛型引數

1.Param 任務執行器需要的資料型別
2.Progress 後臺計算中使用的進度單位資料型別
3.Result 後臺計算返回結果的資料型別
在設定引數時通常是這樣的:String... params,這表示方法可以有0個或多個此型別引數;有時引數可以設定為不使用,用Void...即可。

四個方法

1.onPreExecute() 執行預處理,它運行於UI執行緒,可以為後臺任務做一些準備工作,比如繪製一個進度條控制元件。
2.doInBackground(Params...)
 後臺程序執行的具體計算在這裡實現,doInBackground(Params...)是AsyncTask的關鍵,此方法必須過載。在這個方法內可以使用publishProgress(Progress...)改變當前的進度值。
3.onProgressUpdate(Progress...) 運行於UI執行緒。如果在doInBackground(Params...) 中使用了publishProgress(Progress...),就會觸發這個方法。在這裡可以對進度條控制元件根據進度值做出具體的響應。
4.onPostExecute(Result) 運行於UI執行緒,可以對後臺任務的結果做出處理,結果就是doInBackground(Params...)的返回值。此方法也要經常過載,如果Result為null表明後臺任務沒有完成(被取消或者出現異常)。
 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

執行程式碼:

new DownloadFilesTask().execute(url1, url2, url3);

將android的POST方法放入doInBackground(URL... url)

// Post方式請求
public static void requestByPost() throws Throwable {
	String path = "https://reg.163.com/logins.jsp";
	// 請求的引數轉換為byte陣列
	String params = "id=" + URLEncoder.encode("helloworld", "UTF-8")
			+ "&pwd=" + URLEncoder.encode("android", "UTF-8");
	byte[] postData = params.getBytes();
	// 新建一個URL物件
	URL url = new URL(path);
	// 開啟一個HttpURLConnection連線
	HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
	// 設定連線超時時間
	urlConn.setConnectTimeout(5 * 1000);
	// Post請求必須設定允許輸出
	urlConn.setDoOutput(true);
	// Post請求不能使用快取
	urlConn.setUseCaches(false);
	// 設定為Post請求
	urlConn.setRequestMethod("POST");
	urlConn.setInstanceFollowRedirects(true);
	// 配置請求Content-Type
	urlConn.setRequestProperty("Content-Type",
			"application/x-www-form-urlencode");
	// 開始連線
	urlConn.connect();
	// 傳送請求引數
	DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
	dos.write(postData);
	dos.flush();
	dos.close();
	// 判斷請求是否成功
	if (urlConn.getResponseCode() == HTTP_200) {
		// 獲取返回的資料
		byte[] data = readStream(urlConn.getInputStream());
		Log.i(TAG_POST, "Post請求方式成功,返回資料如下:");
		Log.i(TAG_POST, new String(data, "UTF-8"));
	} else {
		Log.i(TAG_POST, "Post方式請求失敗");
	}
}

//***************************************************分割*************************************************************

在使用if(HTTP_200 == urlConn.getResponseCode())我在考慮getResponseCode()是不是一個阻塞方法(這裡一定是,不然網路會一直失敗),如果是阻塞那麼會維持多久,多久後會給你網路程式碼編號?


這就很奇怪了,在URLConnection.java並沒有表現出來是阻塞方法,但是其中httpURLConnect.java和URLConnection.java都是抽象類(abstract類)當我們呼叫抽象類的方法,經過查閱資料stackoverflow,發現具體的實現機制在底層sun.net.www.protocol.http.HttpURLConnection.。


這裡我猜想java.net.HttpURLConnection和sun.net.www.protocol.http.HttpURLConnection存在繼承關係,java.net.HttpURLConnection繼承了java.net.URLConnection.java抽象方法,同時java.net.HttpURLConnection自己也是抽象類,一些實體實現對應到sun.net.www.protocol.http.HttpURLConnection中(這裡sun.net.www.protocol.http.HttpURLConnection繼承java.net.HttpURLConnection),在我們使用對應方法的時候就會呼叫實現實體(也可以說是重寫後的方法)。


getResponseCode()的阻塞實現也就找到了,在getInputStream()中。