編輯:關於Android編程
一.AsyncTask的簡介
在Android中實現異步任務機制有兩種方式,Handler和AsyncTask。
Handler模式需要為每一個任務創建一個新的線程,任務完成後通過Handler實例向UI線程發送消息,完成界面的更新,這種方式對於整個過程的控制比較精細,但也是有缺點的,例如代碼相對臃腫,在多個任務同時執行時,不易對線程進行精確的控制。關於Handler的相關知識,前面也有所介紹,不清楚的朋友們可以參照一下。為了簡化操作Android1.5提供了工具類android.os.AsyncTask,它使創建異步任務變得更加簡單,不再需要編寫任務線程和Handler實例即可完成相同的任務。
AsyncTask,即異步任務,是Android給我們提供的一個處理異步任務的類.通過此類,可以實現UI線程和後台線程進行通訊,後台線程執行異步任務,並把結果返回給UI線程.
我通常會把代碼的邏輯想成現實生活中的某些現象,加以理解!以前的博客的都沒有把這類想法寫在博客,是怕誤導別人!以後的博客我會加上這部分,僅僅是為了自己的回憶和理解!
AsyncTask,為什麼需要這個東西呢?
因為每個程序就只有一個主線程,就像我們公司中某個項目的項目管理者,負責展示項目(顯示UI)等操作,可是他不可能一個人做完一整個項目,需要其他人的幫忙做其他的事情,這也就好比是線程了!讓線程去做一些耗時的操作,然後做完就告訴項目負責人,做完了,可以更新我們的項目了(更新UI)!那幫忙做事的人也不可能就一個人,一個人的效率太低了,可能已一隊人,也就是線程池了!AsyncTask也就是把這一麻煩的過程給封裝好了,可以理解為AsyncTask是這個過程規范!
二.AsyncTask的方法
構建AsyncTask子類的泛型參數
AsyncTask
Params:啟動任務時輸入的參數類型.
Progress:後台任務執行中返回進度值的類型.
Result:後台任務執行完成後返回結果的類型.
構建AsyncTask子類的回調方法
AsyncTask主要有如下幾個方法:
doInBackground:必須重寫,異步執行後台線程要完成的任務,耗時操作將在此方法中完成.
onPreExecute:執行後台耗時操作前被調用,通常用於進行初始化操作.
onPostExecute:當doInBackground方法完成後,系統將自動調用此方法,並將doInBackground方法返回的值傳入此方法.通過此方法進行UI的更新.
onProgressUpdate:當在doInBackground方法中調用publishProgress方法更新任務執行進度後,將調用此方法.通過此方法我們可以知曉任務的完成進度.
三.示例
演示一個典型的異步處理的實例--加載網絡圖片.網絡操作作為一個不穩定的耗時操作,從4.0開始就被嚴禁放入主線程中.所以在顯示一張網絡圖片時,我們需要在異步處理中下載圖片,並在UI線程中設置圖片。
代碼中主要是onPreExecute,doInBackground,onPostExecute方法中進行操作,我們可以理解為:項目的負責人發布了一項任務,需要完成,因此他用AsyncTask這個規范去執行(execute()),任何的任務都基本是三個部分,事前准備(onPreExecute),執行工作(doInBackground),完成結果(onPostExecute)!
好了,看下界面效果和代碼,自己聯想下!
還有一點,這裡用到網絡操作,記得加權限喔!
package com.liangdianshui.asynctaskdemo; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; public class DownloadImageActivity extends Activity { private ProgressBar mProgress; private ImageView mIvDownloadImage; private static String Url ="http://img5.imgtn.bdimg.com/it/u=794383953,3828916890&fm=21&gp=0.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_download_image); initView(); new MyAsyncTask().execute(Url); } private void initView() { mProgress = (ProgressBar) findViewById(R.id.progress); mIvDownloadImage = (ImageView) findViewById(R.id.iv_image_download); } /** * Params:啟動任務時輸入的參數類型. doInBackground() * Progress:後台任務執行中返回進度值的類型.onProgressUpdate() * Result:後台任務執行完成後返回結果的類型.onPostExecute() */ class MyAsyncTask extends AsyncTask{ //進行異步任務的處理. @Override protected Bitmap doInBackground(String... params) { //獲取傳進來的第一個參數 String url = params[0]; Bitmap bitmap = null; try { /** * No address associated with hostname * 報上面的錯誤原因:1.沒有設置連網的權限 2.手機沒開網絡 */ //打開鏈接 URLConnection urlConnection = new URL(url).openConnection(); InputStream inputStream = urlConnection.getInputStream(); BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); //為了更清楚的顯示,在線程休眠3s Thread.sleep(3000); bitmap = BitmapFactory.decodeStream(bufferedInputStream); //記得關閉流 bufferedInputStream.close(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return bitmap; } //異步處理前的操作 @Override protected void onPreExecute() { super.onPreExecute(); //將ProgressBar設置為可見的 mProgress.setVisibility(View.VISIBLE); } //異步處理後的操作 //bitmap是doInBackground操作後返回的值 @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); //操作完成後把進程顯示隱藏,並把異步下載的圖片顯示在ImageView中 mProgress.setVisibility(View.GONE); mIvDownloadImage.setImageBitmap(bitmap); } } }
第二個示例是“加載進條”
我們看下示例的效果吧:
這裡看起來好像沒啥問題啊,可是仔細看,你會發現,當加載進度條加載到一半的時候,你按返回鍵,再加載進度條,你會發現,要等待一段時間才會加載!這是為什麼呢?
因為:AsyncTask是基於線程池進行實現的,當一個線程沒有結束時,後面的線程是不能執行的.所以必須等到第一個task的for循環結束後,才能執行第二個task.我們知道,當點擊BACK鍵時會調用Activity的onPause()方法.為了解決這個問題,我們需要在Activity的onPause()方法中將正在執行的task標記為cancel狀態,在doInBackground方法中進行異步處理時判斷是否是cancel狀態來決定是否取消之前的task.
這就好像是項目的負責人,發布了一項任務,那一隊人就在干這項任務(線程池執行操作,也就是doInBackground方法的操作),好了今天做到一半,明天上班上班,會繼續干這個任務,而不會停下來,重新執行這個任務或者干另一個任務!因為他沒有接收到負責人的命令!因此當按了返回鍵的時候,我們再點擊加載進度條,項目的負責人需要告訴他們這個項目暫時不做了(也就是把執行的task標記為cancel狀態),然後工人就判斷這個任務是否有這個狀態,有這個狀態就停止不干了!
加上了cancel後的效果圖是這樣的:
代碼:
package com.liangdianshui.asynctaskdemo; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.widget.ProgressBar; public class ProgressActivity extends Activity { private ProgressBar mProgress; private MyAsyncTask mAsyncTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_progress); mProgress = (ProgressBar) findViewById(R.id.pro_show_progress); mAsyncTask=new MyAsyncTask(); mAsyncTask.execute(); } class MyAsyncTask extends AsyncTask{ @Override protected void onPreExecute() { super.onPreExecute(); mProgress.setProgress(0); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); mProgress.setProgress(values[0]); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); } @Override protected Void doInBackground(Void... params) { for (int i = 0; i < 100; i++) { //如果task是cancel狀態,則終止for循環 if (isCancelled()) { break; } //調用publishProgress方法將自動觸發onProgressUpdate方法,把參數傳進去,來進行進度條的更新. publishProgress(i); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } } ; @Override protected void onPause() { super.onPause(); if (mAsyncTask != null && mAsyncTask.getStatus() == AsyncTask.Status.RUNNING) { //cancel方法只是將對應的AsyncTask標記為cancelt狀態,並不是真正的取消線程的執行. mAsyncTask.cancel(true); } } }
我們已經有文章向你描述如何使用<include />標簽來重用和共享你的布局代碼。這篇文章將向你闡述<merge />標簽的使用以及如何與<
Android:BroadcastReceiver注冊的方式分為兩種:靜態注冊動態注冊1. 靜態注冊在AndroidManifest.xml裡通過標簽聲明屬性說明:<
應用已經開發出來了,下一步我們需要思考推廣方面的工作。那麼如何才能讓更多的用戶知道並使用我們的應用程序呢?在手機領域,最常見的做法
本文將介紹Android中Resource Types的drawable、menu、layout。如需訪問官方原文,您可以點擊這些鏈接:《Drawable Resourc