Android UI Operation in Thread

Painless Threading (無痛苦使用線程)

 

本文討論Android應用程序的線程模型以及應用程序應該如何建立工做線程而不是使用主線程來處理長期運行的操做, 以獲得好的UI性能. 本文還解釋了你能夠用來和Android UI組件交互以及建立線程的 API. html

The UI thread UI 線程

 

 

當一個應用程序啓動時, 系統建立一個叫作"main"的線程. 這個主線程也叫UI線程, 它很是重要, 由於它負責將事件分發給合適的widget來處理, 包括繪圖事件等. 它也是你的應用程序和運行中的Android UI組件進行交互的線程. 例如, 若是你按下屏幕上的按鈕, UI線程會將這個觸摸事件分配給該widget, 而該widget將設置它的按下狀態並向事件隊列一個重繪請求. UI線程從隊列中取出請求並通知widget來重畫自身. android

 

單線程模型可能會致使性能不好, 除非你的程序被正確的實現. 特別的, 若是每件事都在同一個線程中進行, 那麼耗時長的操做(例如網絡訪問和數據庫查詢)將阻塞UI線程, 從而使整個UI沒法交互. 在耗時操做進行時, 包括繪畫事件在內的全部事件都沒法進行分配. 在用戶看來, 該應用程序中止了響應. 更糟糕的是, 若是UI線程被阻塞超過一段時間(當前的限制是5秒鐘), 那麼用戶將看到"應用程序無響應"的對話框. 數據庫

 

若是你但願看看這是多麼的糟糕, 那麼你能夠寫一個程序, 建立一個按鈕, 它的OnClickListener中調用Thread.sleep(2000). 那麼該按鈕在按下去之後要等2秒纔會談起, 這時候用戶是很是容易感受到程序很慢. 安全

 

總之, 應用程序UI的響應速度是很重要的, 因此應該避免阻塞UI線程. 若是你須要進行耗時操做, 那麼你應該在其餘的線程中進行(後臺或者工做線程). 網絡

 

下面的例子演示瞭如何實現一個單擊監聽器來下載一個圖片並將它顯示在 ImageView中: less

public void onClick(View v) {
  
new Thread(new Runnable() {
    
public void run() {
      
Bitmap b = loadImageFromNetwork();
      mImageView
.setImageBitmap(b);
    
}
  
}).start();
}
工具

 

一開始, 這段代碼看起來是個不錯的解決方案, 由於它不會阻塞線程. 不幸的是, 它破壞了UI的單線程模型: Android UI工具不是線程安全的, 必須在UI線程中操做. 在上面的代碼段中, ImageView在一個工做線程中操做, 這回致使很奇怪的問題. 追蹤和解決這樣的bug是很是困難的. post

 

Android提供了一些從其它線程中訪問UI線程的方法. 你可能已經對它們之中的某些比較熟悉了: 性能

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)
  • Handler

 

你能夠使用上面的任意一種類和方法來改正以前的錯誤: url

public void onClick(View v) {
  
new Thread(new Runnable() {
    
public void run() {
      
final Bitmap b = loadImageFromNetwork();
      mImageView
.post(new Runnable() {
        
public void run() {
          mImageView
.setImageBitmap(b);
        
}
      
});
    
}
  
}).start();
}

 

不幸的是, 這些類和方法也會使你的代碼更加複雜. 若是你須要實現頻繁的UI更新的話就更糟糕了.

 

爲解決這個問題, Android1.5以上的平臺提供了一個叫作AsyncTask的工具類.

 

Android1.0和1.1上也有和它等效的類叫作UserTask, 它提供了徹底同樣的接口.

 

AsyncTask的做用是幫你來管理線程. 咱們將以前的例子用AsyncTask來重寫:

public void onClick(View v) {
  
new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask<string, void,="" bitmap=""> {
     
protected Bitmap doInBackground(String... urls) {
         
return loadImageFromNetwork(urls[0]);
     
}

     
protected void onPostExecute(Bitmap result) {
         mImageView
.setImageBitmap(result);
     
}
 
}

 

AsyncTask必須使用建立子類的方式來使用. AsyncTask實例只能在UI線程中建立,而且只能運行一次. AsyncTask documentation 中有它的詳細介紹, 這裏簡單介紹一下:

 

 

 

不管你是否使用 AsyncTask, 記住如下關於單線程模型的兩條規則:

  1. 不要阻塞UI線程, 以及
  2. 肯定你只在UI線程中訪問Android UI 工具.

AsyncTask 只是讓上面兩件事情變得更加方便.

http://blog.csdn.net/lmhit/article/details/5584162

相關文章
相關標籤/搜索