Android:非同步處理之Handler+Thread的應用(一)

來源:互聯網
上載者:User

標籤:android   style   blog   http   io   color   ar   os   使用   

前言

  很久很久以前就聽說了,每一個android的應用程式都會分別運行在一個獨立的dalvik虛擬機器進程中,而在每個虛擬機器在啟動時會運行一個UI主線程(Main Thread),而為啥叫UI主線程而不是AI主線程或者是BI主線程呢?因為它要處理全部和UI相關的事件;因為Android系統採用的是UI單執行緒模式,只能由UI主線程對其進行UI操作,如果子線程抱著眾人拾柴火焰高的覺悟來幫忙UI主線程更新UI介面的話,對不起哦~Android系統就會報錯的。粗俗點講就是:我們只能通過UI主線程來蹂躪UI介面,但是其他線程來的話會被告弓雖女幹滴。。

  那麼現在問題來了!鑒於近來挖掘機那麼火,我也不好意思繼續問這個問題了。。。嗯嗯~網路操作之類耗時操作就像挖掘機那樣,我們在下載檔案的時候一樣跟挖掘機挖個大坑一樣需要一定的時間;當挖掘機司機挖好一個大坑要找老闆反饋工作完成一樣,我們下載好一個檔案自然要馬上告訴螢幕前苦逼等待的使用者們,誰知道他們多著急想看**.avi呢;但是你在挖坑時好意思叫老闆在旁邊看你嗎?老闆分分鐘為幾千萬上下的事忙著呢~所以嘛同理,對於網路操作,我們當然也不能在UI主線程中進行網路操作,因為這樣會阻塞主線程造成介面卡死,也會造成ANR(應用程式無響應)。我們應該把檔案下載、檔案讀取諸如此類的耗時操作放到子線程中去進行,等到子線程耗時操作完成時通知UI介面做出響應。

不要在UI主線程中進行耗時操作

  如果你不信邪一定要在UI主線程進行下載檔案、載入大檔案之類的耗時操作。如下代碼:

private Button btn;//onCreate之類的生命週期的方法就是允許在UI主線程中@Overrideprotected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);          btn = (Button) findViewById(R.id.btn);          btn.setOnClickListener(new OnClickListener() {    @Override    public void onClick(View v) {      downLoad();//調用UI主線程的下載函數    }  });}    private void downLoad(){  try {    Thread.sleep(10000);//休眠10秒,類比網路檔案下載耗時操作  } catch (InterruptedException e) {    e.printStackTrace();  }}

你會發現介面卡主了10秒:(類比下載操作的按鈕為深色,說明按鈕一直為按下狀態)

如果這時候你手比較管不住的話,雖然點幾下介面,沒事~Androi系統會馬上送你一份ANR大禮哦,而且還不用998元耶!

小結一個:不要在UI主線程中進行耗時操作,你可能會疑問什麼是UI主線程,UI主線程主要啟動並執行就是Activity、Service等裡面的生命週期方法,所以不要在生命週期方法如onCreate()中進行下載這些大事件。對於耗時操作,我們應該建立一個子線程並交給他處理,但是還需要注意一點。

不要在子線程中更新UI介面

  既然我們說下載檔案要在子線程中進行,那麼我們就建立一個子線程把下載操作放到裡面進行咯,代碼如下:

protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);          btn = (Button) findViewById(R.id.btn);  text = (TextView) findViewById(R.id.text);          btn.setOnClickListener(new OnClickListener() {    @Override    public void onClick(View v) {      new Thread(){        @Override        public void run() {          //在子線程中進行下載操作          try {            Thread.sleep(10000);//休眠10秒,類比耗時操作          } catch (InterruptedException e) {            e.printStackTrace();          }          text.setText("下載完成");//設定TextView,通知UI介面下載完成        }      }.start();    }  });}

10秒後,你覺得會在UI介面完美顯示“下載完成”嗎?一般,出現這個才符合Androi系統的一貫作風

並且在Log中報錯如下

小弟英語其實很廢柴,但是隱隱約約有人告訴我:這不是叫只能在主線程中更新UI嗎?不信,金山翻譯一下去呀。。。。

小結一個:不要在子線程中更新UI介面,這樣會導致android系統報錯、應用崩潰退出。UI介面時單線程模式,我們只能通過UI主線程中對UI的介面進行相關的更新,千萬不要越線辦事,你要記住的是~UI介面是UI主線程的老婆,你們這些子線程誰都別想動!

利用Thread+Handler進行非同步處理

  那麼問題來了,現在我們需要進行耗時操作(例如下載檔案)時不能在主線程執行,我們又需要在UI介面通知使用者我們活幹完了不能再子線程中執行。這似乎是一個棘手的熱山芋呀,幸好Google給我們提供了一個救我們於危難之中的Handler,一個能讓主線程監聽子線程發送來訊息的東東,至於Handler的實現原理我會在後面的文章詳細介紹,現在我們只需要先瞭解Handler的用法。

private Button btn;private TextView text;    private Handler handler = new Handler(){  private int process = 0;  @Override  public void handleMessage(Message msg) {    switch(msg.what){    case 0://更細下載進度      process += 1;      text.setText("下載" + process + "%");//在主線程中更新UI介面      break;    case 1://提示下載完成      text.setText("下載完成");//在主線程中更新UI介面      break;    default:      break;    }  }};//onCreate之類的生命週期的方法就是允許在UI主線程中@Overrideprotected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);          btn = (Button) findViewById(R.id.btn);  text = (TextView) findViewById(R.id.text);          btn.setOnClickListener(new OnClickListener() {  @Override  public void onClick(View v) {    new Thread(){      @Override      public void run() {        //在子線程中進行下載操作        for(int i = 0; i < 100; i++){          try {            Thread.sleep(200);//休眠0.2秒,類比耗時操作          } catch (InterruptedException e) {            e.printStackTrace();          }          handler.sendEmptyMessage(0);//發送訊息到handler,通知下載進度        }        handler.sendEmptyMessage(1);//發送消失到handler,通知主線程下載完成        }      }.start();    }  });}

 這裡來解釋一下Handler的使用方法:

1、我們為了不阻塞主線程,將下載任務通過子線程來執行。

new Thread(){  @Override  public void run() {    //在子線程中進行下載操作    for(int i = 0; i < 100; i++){      try {        Thread.sleep(200);//休眠0.2秒,類比耗時操作      } catch (InterruptedException e) {        e.printStackTrace();      }      handler.sendEmptyMessage(0);//發送訊息到handler,通知下載進度    }    handler.sendEmptyMessage(1);//發送消失到handler,通知主線程下載完成  }}.start();

2、當子線程需要跟主線程交流時,也就是當子線程要跟UI主線程說:親,偶下載檔案到80%了或者偶已經把檔案下載完成了!執行這句代碼

handler.sendEmptyMessage(1);//發送消失到handler,通知主線程下載完成

3、當發送空訊息之後,在Handler將會收到子線程發來的訊息,觸發回調方法handlerMessage(),我們就在這裡對UI介面進行更新,這個回調方法是運行在UI主線程的

@Overridepublic void handleMessage(Message msg) {  switch(msg.what){  case 0://更細下載進度    process += 1;    text.setText("下載" + process + "%");//在主線程中更新UI介面    break;  case 1://提示下載完成    text.setText("下載完成");//在主線程中更新UI介面    break;  default:    break;  }}

4、最後,UI介面更新成功!(圖嘛,我這裡就不上了。。。。)

小結一個:對於比較耗時間的任務,我們一般需要放在子線程中執行;當子線程更新UI介面時,子線程可以通過Handler來通知主線程更新,一般通過發送訊息來觸發handlerMessage()這個回調方法來執行UI介面的更新。

進一步簡略de操作:handler.post方法和view.post方法

  但是如果你覺得每次都要重寫handlerMessage()比較麻煩,我們完全可以用更加簡略的方法來解決我們的需求,就是用handler中的post方法。代碼如下

new Thread(){  @Override  public void run() {    //在子線程中進行下載操作    try {      Thread.sleep(1000);    } catch (InterruptedException e) {      e.printStackTrace();    }    handler.post(new Runnable() {      @Override      public void run() {        text.setText("下載完成");      }    });//發送消失到handler,通知主線程下載完成  }}.start();

  這樣處理的話我們就可以不用重寫handlerMessage()方法了,適合子線程與主線程進行較為單一的交流。但在這裡我們要強調的一點的是,post裡面的Runnable還是在UI主線程中啟動並執行,而不會另外開啟線程運行,千萬不要在Runnable的run()裡面進行耗時任務,不然到時又ANR了可別找我哦。。

如果你有時候連handler都不想搞,還可以這樣寫代碼滴。

我們只需要把handler換成View組件進行post,更新任務自然會載入到UI主線程中進行處理。

text.post(new Runnable() {  @Override  public void run() {    text.setText("下載完成");  }});//發送消失到handler,通知主線程下載完成

至於Handler機制以及這兩種post的原理,我將會在後面的部落格文章中專題介紹,這裡只提供一個使用方法而已。

 

終於寫完了睡覺,怎麼沒有掌聲呢??雞蛋、啤酒瓶砸幾個上來~~~~哈哈

 

enjoy風鈴
出處:http://www.cnblogs.com/net168/
本文著作權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則下次不給你轉載了。

Android:非同步處理之Handler+Thread的應用(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.