Android 線程模型和 AsyncTask

  android 的線程模型:當一個 android 的應用運行後, 就會有一個 UI 的 main 線程啓動 , 這是一個非常重要的線程,它負責把事件分派到相應的控件,其中就包括屏幕繪圖事件,它同樣是用戶與 android 控件 交互的線程。比如,當你在屏幕上的 EditText 上輸入文字, UI 線程會把這個事件分發給剛輸入文字的 EditText ,緊接會向事件隊列發送一個更新 ( invalidate )請求。 UI 線程會把這個請求移出事件隊列並通知 EditText 在屏幕上重新繪製自身。 
       這種單線線程模型就會使得 android 的應用程序性能低下, 如果在這個單線程裏執行一些耗時的操作, 比如訪問數據庫, 或是從網絡端下載圖片,就會會阻塞整個用戶界面。 比如如下操作:

         Bitmap b =  loadImageFromNetwork(); 

這個操作非常耗時, 在這種情況下你會發現 , 界面僵死在那裏並且 android 在系統 5 秒中後沒有反應,會顯示一個關閉或等待的錯誤。

         也許我們可以使用一個新的 Thread 來解決它

  1. new Thread(new Runnable() {    
  2.                  public void run() {                           
  3.                          Bitmap b = loadImageFromNetwork();      
  4.                         mImageView.setImageBitmap( b );      
  5.                  }    
  6.              }).start();   

 

但這樣會發生一些很難察覺的錯誤, 因爲我們知道 UI 線程不是線程安全的。當然有很多種方法來處理這個問題: 
android 提供了幾種在其他線程中訪問 UI 線程的方法。 
• Activity.runOnUiThread( Runnable )
• View.post( Runnable )
• View.postDelayed( Runnable, long )
• Hanlder

  1. new Thread( new Runnable() {      
  2.             public void run() {      
  3.                      final Bitmap b = loadImageFromNetwork();      
  4.                      mImageView.post( new Runnable() {      
  5.                      mImageView.setImageBitmap( b );      
  6. });      
  7.           }      
  8. }).start();  

這種方法比較繁瑣,同時當你需要實現一些很複雜的操作並需要頻繁地更新UI 時這會變得更糟糕。爲了解決這個問題,android 提供了一個工具類:AsyncTask ,它使創建需要與用戶界面交互的長時間運行的任務變得更簡單。

       就拿加載網絡圖片舉個例子:

[c-sharp] view plaincopy
  1. ublic class CanvasImageTask extends AsyncTask<ImageView, Void, Bitmap>{  
  2.         private ImageView gView ;  
  3.           
  4.     protected Bitmap doInBackground(ImageView... views) {  
  5.                 Bitmap bmp = null ;  
  6.                 ImageView view = views[0];  
  7.             // 根據iconUrl獲取圖片並渲染,iconUrl的url放在了view的tag中。  
  8.             if (view.getTag() != null) {  
  9.                     try {  
  10.                        URL url = new URL(view.getTag().toString());  
  11.                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
  12.                        conn.setDoInput(true);  
  13.                        conn.connect();  
  14.                        InputStream stream = conn.getInputStream();  
  15.                        bmp = BitmapFactory.decodeStream(stream);  
  16.                        stream.close();  
  17.                     } catch (Exception e) {  
  18.                                 Log.v("img", e.getMessage());  
  19.                             return null;  
  20.                     }  
  21.             }  
  22.             this.gView = view;  
  23.             return bmp;  
  24.     }  
  25.     protected void onPostExecute(Bitmap bm) {  
  26.             if (bm != null) {  
  27.                     this.gView.setImageBitmap(bm);  
  28.                     this.gView = null ;  
  29.             }  
  30.     }  
  31.       
  32. }  
  33. 在Activity中直接調用  
  34. if(!img.isDrawingCacheEnabled() || !holder.image.getTag().equals(imgpath)){  
  35.                 img.setImageResource(R.drawable.icon_app);  
  36.                 img.setTag(imgpath);  
  37.                 try{  
  38.                     new CanvasImageTask().execute(img);  
  39.                     img.setDrawingCacheEnabled(true);  
  40.                 }catch (Exception e) {  
  41.                     Log.e("error""RejectedExecutionException in content_img: " +  imgpath);  

這樣圖片加載使用異步線程便不會進行堵塞發生錯誤,我們還可以使用 callback 在圖片加載完後進行回調

 

  1. public class CanvasImageTaskCall extends AsyncTask<ImageView, Void, Bitmap> implements Callback{  
  2.     private ImageView gView ;  
  3.       
  4.     protected Bitmap doInBackground(ImageView... views) {  
  5.             Bitmap bmp = null ;  
  6.             ImageView view = views[0];  
  7.             // 根據iconUrl獲取圖片並渲染,iconUrl的url放在了view的tag中。  
  8.             if (view.getTag() != null) {  
  9.                     try {  
  10.                        URL url = new URL(view.getTag().toString());  
  11.                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
  12.                        conn.setDoInput(true);  
  13.                        conn.connect();  
  14.                        InputStream stream = conn.getInputStream();  
  15.                        bmp = BitmapFactory.decodeStream(stream);  
  16.                        stream.close();  
  17.                     } catch (Exception e) {  
  18.                             e.printStackTrace();  
  19.                             Log.v("img", e.getMessage());  
  20.                             Message msg = new Message();  
  21.                             msg.what = 0;  
  22.                             handleMessage(msg);  
  23.                             return null;  
  24.                     }  
  25.             }  
  26.             this.gView = view;  
  27.             return bmp;  
  28.     }  
  29.     protected void onPostExecute(Bitmap bm) {  
  30.             if (bm != null) {  
  31.                 this.gView.setImageBitmap(bm);  
  32.                 this.gView.setTag(bm);  
  33.                 this.gView = null ;  
  34.                 Message msg = new Message();  
  35.                 msg.what = 1;  
  36.                 handleMessage(msg);  
  37.             }  
  38.     }  
  39.     public boolean handleMessage(Message msg) {  
  40.         // TODO Auto-generated method stub  
  41.         return false;  
  42.     }  
  43.       
  44. }  

在 Activity 中直接調用

 

  1. new CanvasImageTaskCall(){  
  2.                         @Override  
  3.                         public boolean handleMessage(Message msg) {  
  4.                                 switch (msg.what) {  
  5.                                 case 0:  
  6.                                         Log.i("test""圖片加載失敗");  
  7.                                         break;  
  8.                                 case 1:  
  9.                                         Log.i("test""圖片加載成功");  
  10.                                         break;  
  11.                                 default:  
  12.                                         break;  
  13.                                 }  
  14.                                 saveButton.setTextColor(Color.WHITE);  
  15.                                 saveButton.setClickable(true);  
  16.                                 bitmap = (Bitmap) imageView.getTag();  
  17.                                 return super.handleMessage(msg);  
  18.                         }  
  19.                 }.execute(img);  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章