Android文章翻譯之Painless Threading – Android移動開發技術文章_手機開發 Android移動開發教學課程

輕松使用線程(Painless Threading)
 
這篇文章介紹瞭Android的線程模型和AsyncTask等內容,值得一看。以下的翻譯的內容:

此文章討論的是用於Android應用程序的線程模型,和應用程序怎樣利用Worker Thread代替主線程執行長時間的操作,用以確保最好的UI表現。該文章同樣解釋瞭應用程序在主線程與worker Thread中和Android UI工具包組件交互的相關API。
UI線程(The UI Thread)
  當應用程序運行的時候,系統會為應用程序創建一個主線程。它同樣被稱作UI 線程,它管理著分派事件給合適的部件,包括繪制事件。同樣它也是你的應用程序和Android UI 控件交互的線程。
  例如:當你觸摸屏幕上的按鈕,UI線程會分派觸摸事件給按鈕,設置按下狀態和發送一個更新請求到事件隊列。UI線程讓請求出隊列並且通知組件重畫自己。
如果你的應用程序設計不合理  單線程模型會造成極低的效率。特別的,如果任何事都在一個線程中執行,在UI線程執行長時間的操作例如網絡連接和數據查詢會阻塞整個用戶界面。這樣會造成沒有事件會被分發,包括繪制事件。用戶會認為程序出現瞭掛載。甚至更糟,UI線程阻塞超過大概5秒就會出現臭名昭著的”application not responding”(ANR)對話框。
  如果你想看看情況有多壞,寫一個簡單的應用程序,繪制一個button,在點擊事件裡調用Thread.sleep(2000)。點擊按鈕,它會在按下狀態停留瞭2秒再回到正常狀態。這樣會讓用戶感覺到應用程序反應很慢。
  做個總結:保證UI線程不被阻塞與你應用程序流暢性關系重大。你應該確保長時間的操作運行在其他的線程(background or worker threads)。
下面是一個下載圖片然後呈現在ImageView的例子:
public void onClick(View v) {   new Thread(new Runnable() {     public void run() {       Bitmap b = loadImageFromNetwork();       mImageView.setImageBitmap(b);     }   }).start(); }
首先,這段代碼看似很好的解決瞭問題,它沒有阻塞UI線程。不幸的是,這違反瞭UI的單線程模型:Android UI控件是非線程安全的,必須在UI線程中操作。在上面這段代碼中,ImageView在worker線程中被操作會導致很多奇怪的問題。跟蹤和改正這樣的bug是很困難且比較耗時的。
 Android提供瞭幾種方法讓其他線程訪問UI線程。你可能已經熟悉瞭一些,下面是完整的列表:
 
·        Activity.runOnUiThread(Runnable) 
·        View.post(Runnable) 
·        View.postDelayed(Runnable,long) 
·        Handler 
你可以用其中的一些方法改正之前的那個例子:
 
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更新時甚至更糟。
為瞭解決這種問題,Android平臺在1.5後提供瞭一個實用的工具類叫做AsyncTask,簡化瞭長時間需要和用戶界面交流的任務。
 
  在Android1.0和1.1中UserTask的作用相當於AsyncTask。
 AsyncTask的目標是幫助你更輕松的管理線程。上一個例子可以利用AsyncTask重寫:
 
public void onClick(View v) { 
  new DownloadImageTask().execute("/wp-content/images1/20181004/20111013014500861184.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的用法,下面是一個讓你快速使用的概要:
你能夠使用泛型指定類型來定制參數,進度值和任務的返回值
  doInBackground()方法是在workerthread中自動調用的
  onPreExecut(),onPostExecut()和onProgressUpdate()是在UI線程中調用的
doInBackground()的返回值傳遞給onPostExecute()
  你可以在doInBackground()中任何時間調用publishProgress()方法使得在UI線程中執行onProgressUpdate()方法
  你能夠在任何線程和任何時候取消任務
在官方文檔中,你可以閱讀幾個復雜的例子的源代碼,如:Shelves(ShelvesActivity.java 和AddBookActivity.java) 和 Photostream(LoginActivity.java,PhototstreamActivity.java和ViewPhotoActivity.java).強烈建議閱讀Shelves的源代碼來學習如何配置改變中保持任務和如何在activity銷毀時適當的取消它們。
 
無論你是否使用AsyncTask,記住單線程模型的兩個規則:
        1:不要阻塞UI線程
        2:確保隻在UI線程中訪問AndroidUI控件
AsyncTask使這兩項變的更簡單去做。

以上就是全部內容,歡迎大傢和我交流。

摘自:ldj299的專欄

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *