標籤:padding 非同步任務 post parse width 擷取 cti puts service
一切搞定。以為高枕無憂了,結果還是有問題!
log開始報錯了,擷取更新資訊異常。。!debug一下。發現Exception:android.os.NetworkOnMainThreadException
這個異常大概意思是在主線程訪問網路時出的異常。 Android在4.0之前的版本號碼 支援在主線程中訪問網路。可是在4.0以後對這部分程式進行了最佳化,也就是說訪問網路的代碼不能寫在主線程中了。
查看網上的解決方案。在Android中實現非同步任務機制有兩種方式,Handler和AsyncTask。
Handler模式須要為每個任務建立一個新的線程,任務完畢後通過Handler執行個體向UI線程發送訊息,完畢介面的更新,這樣的方式對於整個過程的控制比較精細,但也是有缺點的。比如代碼相對臃腫,在多個任務同一時候運行時,不易對線程進行精確的控制。
為了簡化操作。Android1.5提供了工具類android.os.AsyncTask。它使建立非同步任務變得更加簡單,不再須要編寫任務線程和Handler執行個體就可以完畢同樣的任務。
這裡我們採用AsyncTask的處理方式。
先來看看AsyncTask的定義:
public abstract class AsyncTask<Params, Progress, Result> {
三種泛型型別分別代表“啟動任務啟動並執行輸入參數”、“背景工作啟動並執行進度”、“後台計算結果的類型”。
在特定場合下。並非全部類型都被使用。假設沒有被使用。能夠用java.lang.Void類型取代。
AsyncTask的運行分為四個步驟
每一步都相應一個回調方法,這些方法不應該由應用程式調用。開發人員須要做的就是實現這些方法。
1) 子類化AsyncTask
2) 實現AsyncTask中定義的以下一個或幾個方法
onPreExecute(), 該方法將在運行實際的後台操作前被UI thread調用。
能夠在該方法中做一些準備工作,如在介面上顯示一個進度條。
doInBackground(Params...), 將在onPreExecute 方法運行後立即運行。該方法運行在後台線程中。這裡將主要負責運行那些非常耗時的後台計算工作。能夠調用 publishProgress方法來更新即時的任務進度。
該方法是抽象方法,子類必須實現。
onProgressUpdate(Progress...),在publishProgress方法被調用後,UI thread將調用這種方法從而在介面上展示任務的進展情況,比如通過一個進度條進行展示。
onPostExecute(Result), 在doInBackground 運行完畢後,onPostExecute 方法將被UI thread調用。背景計算結果將通過該方法傳遞到UI thread.
為了正確的使用AsyncTask類。下面是幾條必須遵守的準則:
1) Task的執行個體必須在UI thread中建立
2) execute方法必須在UI thread中調用
3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個方法
4) 該task僅僅能被運行一次。否則多次調用時將會出現異常
doInBackground方法和onPostExecute的參數必須相應。這兩個參數在AsyncTask聲明的泛型參數列表中指定。第一個為 doInBackground接受的參數,第二個為顯示運行進度的參數。第第三個為doInBackground返回和onPostExecute傳入的參數。
以下是項目中詳細的處理方法:
package com.liuhao.mobilesafe.engine;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import android.content.Context;import android.os.AsyncTask;import com.liuhao.mobilesafe.domain.UpdateInfo;public class UpdateInfoService {private Context context; //應用程式環境的上下文資訊public UpdateInfoService(Context context) {this.context = context;}// 將與網路通訊的過程封裝在ServiceInBackGround的doInBackground方法中private class ServiceInBackGround extends AsyncTask<Integer, Void, UpdateInfo>{@Overrideprotected UpdateInfo doInBackground(Integer... params) {String path = context.getResources().getString(params[0]); //依據urlId擷取資源檔裡相應的內容UpdateInfo info = new UpdateInfo();URL url;try {url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(20000);conn.setRequestMethod("GET");InputStream is = conn.getInputStream(); //得到url相應的檔案流。應該是xml檔案流,須要對其進行解析info = UpdateInfoParser.getUpdateInfo(is); //對xml檔案流進行解析,擷取到更新資訊實體} catch (Exception e) {e.printStackTrace();}return info;}@Overrideprotected void onPostExecute(UpdateInfo result) {super.onPostExecute(result);}}/** * @param urlId * server資源路徑相應的id * @return 更新資訊 * @throws Exception */public UpdateInfo getUpdateInfo(int urlId) throws Exception {//new serviceInBackGround().execute(urlId).get();return new ServiceInBackGround().execute(urlId).get();}}
最後須要說明AsyncTask不能全然代替線程,在一些邏輯較為複雜或者須要在後台重複啟動並執行邏輯就可能須要線程來實現了。
異常都解決後。再次執行程式:
點擊進入程式,會彈出升級對話方塊:
查看日誌:
使用者點擊確定:
點擊取消:
參考:
http://www.cnblogs.com/dawei/archive/2011/04/18/2019903.html
http://daoshud1.iteye.com/blog/1843655
【邊做項目邊學Android】異常處理:android.os.NetworkOnMainThreadException--多線程問題