AsyncTask是抽象類別,子類必須實現抽象方法doInBackground(Params... p) ,在此方法中實現任務的執行工作,比如連接網路獲取資料等。通常還應該實現onPostExecute(Result r)方法,因為應用程式關心的結果在此方法中返回。需要注意的是AsyncTask一定要在主執行緒中創建實例。AsyncTask定義了三種泛型類型Params,Progress和Result。
- Params 啟動任務執行的輸入參數,比如HTTP請求的URL。
- Progress 幕後工作執行的百分比。
- Result 後臺執行任務最終返回的結果,比如String。
AsyncTask的執行分為四個步驟,與前面定義的TaskListener類似。每一步都對應一個回檔方法,需要注意的是這些方法不應該由應用程式調用,開發者需要做的就是實現這些方法。在任務的執行過程中,這些方法被自動調用。
- onPreExecute() 當任務執行之前開始調用此方法,可以在這裡顯示進度對話方塊。
- doInBackground(Params...) 此方法在後臺執行緒執行,完成任務的主要工作,通常需要較長的時間。在執行過程中可以調用publicProgress(Progress...)來更新任務的進度。
- onProgressUpdate(Progress...) 此方法在主執行緒執行,用於顯示任務執行的進度。
- onPostExecute(Result) 此方法在主執行緒執行,任務執行的結果作為此方法的參數返回。
PageTask擴展了AsyncTask,在doInBackground()方法中讀取網頁內容。PageTask的原始程式碼如下所示:
- // 設置三種類型參數分別為String,Integer,String
- class PageTask extends AsyncTask
{ - // 可變長的輸入參數,與對應
- @Override
- try {
- HttpClient client = new DefaultHttpClient();
- // params[0]代表連接的url
- HttpGet get = new HttpGet(params[0]);
- String s = null;
- if (is != null) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buf = new byte[128];
- int ch = -1;
- int count = 0;
- count += ch;
- if (length > 0) {
- // 如果知道回應的長度,調用publishProgress()更新進度
- publishProgress((int) ((count / (float) length) * 100));
- }
- // 為了在模擬器中清楚地看到進度,讓執行緒休眠100ms
- }
- // 返回結果
- return s;
- } catch (Exception e) {
- }
- return null;
- }
- @Override
- protected void onCancelled() {
- }
- @Override
- protected void onPostExecute(String result) {
- // 返回HTML頁面的內容
- }
- @Override
- protected void onPreExecute() {
- // 任務啟動,可以在這裡顯示一個對話方塊,這裡簡單處理
- }
- @Override
- // 更新進度
- }
- }
執行PageTask非常簡單,只需要調用如下代碼。重新運行NetworkActivity,不但可以抓取網頁的內容,還可以即時更新讀取的進度。讀者嘗試讀取一個較大的網頁,看看百分比的更新情況。
- PageTask task = new PageTask();
Android SDK文件範例
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"); } }
Once created, a task is executed very simply:
new DownloadFilesTask().execute(url1, url2, url3);
Android 中的AsyncTask的使用心得
在android程序中一定不能阻塞UI线程,否则很容易就会弹出no respond 的对话框,导致程序退出。为了避免这种情况,一般需要较长时间执行的任务都放在线程中去执行,如从网上下载图片在界面的某个区域显示。但是使用线程回导致cpu开销过大,并且当线程管理不好时也会弹出no respond框。android提供了AsyncTask类用来处理这种情况;例如需要下载图片,然后在songImagButton中显示,下载的逻辑在songImageButton的initImage方法中。
- private class DrawImageTask extends AsyncTask
{ - //更新图片显示区域,显示图片
- @Override
- protected void onPostExecute(Void params) {
- // TODO Auto-generated method stub
- songImageButton.invalidate();
- this.cancel(false);
- }
- //下载图片
- @Override
- protected Void doInBackground(Void... params) {
- // TODO Auto-generated method stub
- songImageButton.initImage();
- return null;
- }
- }
一般在doInBackground中执行后台的逻辑,如下载图片或其他需要耗时长的任务,onPostExecute方法用来对界面进行操作。如果后台的逻辑有返回值,则由doInBackground返回然后传入onPostExecute方法,然后更新界面。doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。
当然我个人认为AsyncTask不能完全取代线程,在一些逻辑较为复杂或者需要在后台反复执行的逻辑就可能需要线程来实现了。
No comments:
Post a Comment