Android 非同步作業AsyncTask

來源:互聯網
上載者:User

非同步輕量級實現;
AsynceTask簡述:

1.功能類似於Handler,都是為了防止UI線程操作阻塞而衍生而來。

2.AsyncTask是Handler的一個輕量級實現,模型類似於IntentService於Service。都是為了更加方便操作。(因為一般的非同步,我們都是開啟一個子線程或是匿名線程,缺點就是樣的實現對於線程的操作,控制是十分困難)

3.闡述下Handler,一般我們就認為Handler既一個Android訊息處理器。預設情況下,他只接受當前線程的訊息執行個體。
但是,當在一個多線程,比如子線程資料處理後更新Ui線程,此時只要存在Handler的指標,簡單的說就是執行個體對象時,
訊息的收發處理就能執行在不同的進程中了,這個也是我們常用到的非同步處理手法。

4.從原始碼中看AsyncTask類中有 線程池,同樣也執行個體化了一個Handler對象。
說白了,AsyncTask只是對以上我們自己用handler,thread實現的非同步做了一個很好的封裝,使用到線程池對於線程的銷毀和建立開銷大大減小

綜合了下:AsyncTask的非同步處理相對於傳統的handler+Thread組合,減少程式中線程過多開銷過大。操作和管理更加方便。

AsyncTask的是實現:
和所有網上說的一樣,該對象必須在UiThread中執行個體化,然後執行execute方法。
copy下:AsyncTask定義了三種泛型型別 Params,Progress和Result。
    •Params 啟動任務執行的輸入參數,比如HTTP請求的URL。
    •Progress 背景工作執行的百分比。
    •Result 後台執行任務最終返回的結果,比如String。
 
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只能被執行一次,否則多次調用時將會出現異常

下面是我看了原始碼書寫下整個流程:

step 1:在UiThread中執行個體化類  執行了父類的構造   

    public AsyncTask() {                 mWorker = new WorkerRunnable{//實現線程接扣的線程類。               public Result call() {                   return doInBackground(mParams);//在類似於線程的run方法中調用doInBackground(mParams);               }           };                 mFuture = new FutureTask(mWorker) {//接受mWorker線程對象,執行個體化FutureTask類來操作線程。              }  

step 2 :在UiThread中調用AsyncTask對象的execute方法。

    public execute(){                           onPreExecute();//此方法中先調用了onPreExecute,也就是我們上文提到的準備工作。                    sExecutor.execute(mFuture);// 然後通過線程池操作構造中我們執行個體化的runnable對象。                    return this;  

step 3 :根據step 2 可以知道 程式這步執行的應該是mFuture 代碼中的done()

    protected void done() {                      Message message;                      Result result = null;              // 發送訊息Tag和 訊息處理結果。訊息處理結果又用AsyncTaskResult類封裝起來,執行個體化對象傳遞進去的result就是上面doInBackground方法執行後的結果。                      message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                              new AsyncTaskResult<Result>(AsyncTask.this, result));                      message.sendToTarget();                  }  

step 4: 根據step 3,很明顯 handler發送,後緊接著就是訊息的處理

    private static class InternalHandler extends Handler {                        @Override             public void handleMessage(Message msg) {                 AsyncTaskResult result = (AsyncTaskResult) msg.obj;                 switch (msg.what) {                     case MESSAGE_POST_RESULT://通過step 3的Tag,執行改方法;                               // There is only one result                         result.mTask.finish(result.mData[0]);                         break;                     case MESSAGE_POST_PROGRESS:                         result.mTask.onProgressUpdate(result.mData);                         break;                     case MESSAGE_POST_CANCEL:                         result.mTask.onCancelled();                         break;                 }             }         }  

step 5: 根據step 4執行  result.mTask.finish

    private void finish(Result result) {            if (isCancelled()) result = null;            onPostExecute(result);// 注意。。執行了onPostExecute            mStatus = Status.FINISHED;        }  

至此我們發現上文提到
onPreExecute()  ----》doInBackground()------》onPostExecute()基本流程方法都遊走一邊

還剩下兩個重新整理進度的 :   onProgressUpdate()和publishProgress();

    protected final void publishProgress(Progress... values) {             sHandler.obtainMessage(MESSAGE_POST_PROGRESS,                     new AsyncTaskResult<Progress>(this, values)).sendToTarget();         }  

從這個方法很容易看出,其實他就是一個Handler訊息發送的實現。
網上一般說可以在doInBackground()調用該方法,然後再回過去看handler執行個體化那段代碼
 case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;

執行了onProgressUpdate()

    該類出現了FutureTask以及callable等java中的類。因為手邊沒有java  源碼。沒有細細讀下

    整個流程大致如上。

 

下面附上一個用過的,也算比較常用的首頁圖片非同步擷取例子代碼:

    public class MainActivity extends BaseActivity implements OnClickListener {                private static final HashMap<String, Drawable> HOMEIMAGECACHE = new HashMap<String, Drawable>();                @Override          public void onCreate(Bundle savedInstanceState) {              super.onCreate(savedInstanceState);              mContext = MainActivity.this;              FrameLayout ll = (FrameLayout) this.getLayoutInflater().inflate(                      R.layout.main, null);              setContentView(ll);              init();              fatchData();                        }                private void fatchData() {              GetHomePageImageTask imageTask = new GetHomePageImageTask();              //首頁圖片擷取測試              String imgUrl = "http://192.168.1.1/img/xxxxx.png,http://192.168.1.1/img/zuqiu2.png,http://192.168.1.1/img/zuqiu3.png";              imageTask.execute(imgUrl);            }          private void init() {              loadView();                        }                private Gallery mGallery;                    /**          *           */          private void loadView() {                            mGallery = (Gallery) findViewById(R.id.homepage_gallery);          }                class GetHomePageImageTask extends AsyncTask<String, Integer, Drawable []>{                    /**              * step 1: 在ui Thread中調用execute()後執行該方法;              * 一般可以做些準備工作。              */              @Override               protected void onPreExecute() {                  // TODO Auto-generated method stub                  super.onPreExecute();              }                             /**               * step 2: 執行後台操作;               */                            @Override              protected Drawable[] doInBackground(String... params) {                                String [] imageUrls= params[0].split(",");              Drawable [] drawables = new Drawable[imageUrls.length];              for(int i = 0; i < imageUrls.length;i++ ){                  drawables[i] = lookupFile(imageUrls[i]);              }                  return drawables;              }                            /**              *在publishProgress方法被調用後,ui線程將調用該方法更新進度;              */              @Override              protected void onProgressUpdate(Integer... values) {                  // TODO Auto-generated method stub                  super.onProgressUpdate(values);                                }                            /**              * step 3:在doInBackground執行完成後i,該方法被Ui線程執行那個調用;              */              @Override              protected void onPostExecute(Drawable[] result) {                  // TODO Auto-generated method stub                  super.onPostExecute(result);                  ImageAdapter adapter = new ImageAdapter(mContext, result);                  mGallery.setAdapter(adapter);              }          }          class ImageAdapter extends BaseAdapter {                    Holder holder;              /* 聲明變數 */              int mGalleryItemBackground;              private Context mContext;                    private Drawable[] _bitmap;                    LayoutInflater inflater;                    /* ImageAdapter的構造器 */              public ImageAdapter(Context c, Drawable[] bitmap) {                  mContext = c;                  _bitmap = bitmap;                                }                    /* 覆蓋的方法getCount,返回圖片數目 */              public int getCount() {                  return _bitmap.length;              }                    /* 覆蓋的方法getItemId,返回映像的數組id */                    public Object getItem(int position) {                  return position;              }                    public long getItemId(int position) {                  return position;              }                    /* 覆蓋的方法getView,返回一View對象 */              public View getView(int position, View convertView, ViewGroup parent) {                  inflater = LayoutInflater.from(mContext);                  if (convertView == null) {                      convertView = inflater.inflate(R.layout.game_detail_item, null);                      holder = new Holder();                      holder.img = (ImageView) convertView                              .findViewById(R.id.game_gallery_img);                      convertView.setTag(holder);                  } else {                      holder = (Holder) convertView.getTag();                  }                  holder.img.setBackgroundDrawable(_bitmap[position]);                  return convertView;              }                    final class Holder {                  ImageView img;              }          }          /*          * 圖片資料讀取          */          public Drawable lookupFile(String url) {              // TODO Auto-generated method stub              FileInputStream fis = null;              Drawable drawable = null;              try {                  if (HOMEIMAGECACHE.get(url) == null) {                      URL u = new URL(url);                      URLConnection openConnection = u.openConnection();                      drawable = Drawable.createFromStream(                              openConnection.getInputStream(), "");                      drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),                              drawable.getIntrinsicHeight());                      HOMEIMAGECACHE.put(url, drawable);                  }                  return HOMEIMAGECACHE.get(url);              } catch (Exception e) {                  // Not there.                  return null;              } finally {                  if (fis != null) {                      try {                          fis.close();                      } catch (IOException e) {                                                }                  }              }          }      }  

程式碼分析:

1.url是裡包含多個圖片的網路地址

2.用了一個gallery來顯示圖片

3.實現自訂的GetHomePageImageTask

4.lookupFile()中用了下緩衝,可以忽略。

主要代碼還是GetHomePageImageTask中的

    /**           * step 2: 執行後台操作;           */                    @Override          protected Drawable[] doInBackground(String... params) {                        String [] imageUrls= params[0].split(",");          Drawable [] drawables = new Drawable[imageUrls.length];          for(int i = 0; i < imageUrls.length;i++ ){              drawables[i] = lookupFile(imageUrls[i]);          }              return drawables;          }  

    /**              * step 3:在doInBackground執行完成後i,該方法被Ui線程執行那個調用;              */              @Override              protected void onPostExecute(Drawable[] result) {                  // TODO Auto-generated method stub                  super.onPostExecute(result);                  ImageAdapter adapter = new ImageAdapter(mContext, result);                  mGallery.setAdapter(adapter);              }  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.