歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android中線程和Handle

相信大家對線程應該不會太陌生了,線程是進程中的實體,它的生命周期:1.新建 2.就緒 3.運行 4.阻塞 5.死亡。

當我們編寫的Android的UI程序運行後,系統創建了一個叫做“main”的線程,我們可以通過Debug模式進行觀看:

這個Main線程也就是主線程,它在Android系統中也叫UI線程。

它負責分發事件給構件,包括繪制事件。例如,當你觸摸屏幕上的一個按鈕時,UI線程會分發一個觸摸事件給構件,

然後,構件會設定自己為被按下的狀態,並拋出一個請求給事件隊列,UI線程隊列接收請求並通知構件繪制自己。

它是非UI安全的,也就是說,不接受非UI線程的修改請求。當我們通過別的線程(非主線程或者說是非原始線程)來修改它的時候,

會拋出這個異常:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

CalledFromWrongThreadException 這個字面上都理解過來了,是說這個請求來自於錯誤的線程。

Only the original thread that created a view hierarchy can touch its views 只有最初創建視圖層次結構的線程才可以接觸到這些視圖。

也就是說android中相關的view和控件不是線程安全的,我們可以采用以下幾種方式:

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

其中我認為最簡單的而且最沒用的就是runOnUiThread了,只要給它一個Runnable,它輕輕松松就運行在UIThread了。但就是因為這個輕輕松松,我們的問題也來了。

因為它是運行在UI線程,也就是給用戶展示和操作的線程,我們用它去執行一些操作的話,這個線程就會進入一個阻塞的狀態,如果阻塞狀態超過5秒的話,系統就

會過來提示你了,這樣給用戶的體驗很不好,如下圖:


這時我們就需要用到上面介紹的另外幾種方式來處理,這裡介紹下一最常用的Handler。

Handler的使用場合:

1 安排messages和runnables在將來的某個時間點執行。

2 將action入隊以備在一個不同的線程中執行。即可以實現線程間通信。

   比如當你創建子線程時,你可以在你的子線程中拿到父線程中創建的Handler對象,就可以通過該對象向父線程的消息隊列發送消息了。

   由於Android要求在UI線程中更新界面,因此,可以通過該方法在其它線程中更新界面。


下面是完整代碼,你可以直接跳過看我後面的斷點調試。

  1. package com.hm;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.os.Message;  
  7. import android.widget.ProgressBar;  
  8. import android.widget.TextView;  
  9.   
  10. public class AutoActivity extends Activity{  
  11.   
  12.     private ProgressBar bar;  
  13.     private TextView textView;  
  14.       
  15.     private MyHandler myHandler;  
  16.       
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.loading);  
  21.           
  22.         myHandler=new MyHandler();//新建一個屬於UI線程的Handle   
  23.         bar=(ProgressBar)findViewById(R.id.progressBar);  
  24.         textView=(TextView)findViewById(R.id.textView);  
  25.           
  26.         new Thread(new MyThread()).start();//新建一個子線程並運行   
  27.     }  
  28.       
  29.     class MyThread implements Runnable{  
  30.   
  31.         @Override  
  32.         public void run() {  
  33.             while(bar.getProgress()<bar.getMax()){  
  34.                 Message msg=new Message();  
  35.                 //這裡可以對msg進行參數傳遞   
  36.                 myHandler.sendMessage(msg);  
  37.                   
  38.                 try {  
  39.                     //每隔1秒睡眠一次   
  40.                     Thread.sleep(1000);  
  41.                 } catch (InterruptedException e) {  
  42.                     // TODO Auto-generated catch block   
  43.                     e.printStackTrace();  
  44.                 }  
  45.             }  
  46.             System.out.println("used for breakPoint");  
  47.   
  48.         }  
  49.           
  50.     }  
  51.       
  52.     class MyHandler extends Handler{  
  53.   
  54.         @Override  
  55.         public void handleMessage(Message msg) {  
  56.             int progress=bar.getProgress()+10;  
  57.             bar.setProgress(progress);  
  58.             textView.setText(String.valueOf(progress));  
  59.             super.handleMessage(msg);  
  60.         }  
  61.           
  62.     }  
  63.   
  64.   
  65. }  
在new Thread(new MyThread()).start();//新建一個子線程並運行 這裡,我加入了一個斷點。運行完這條語句後,可以清楚地看到我們的虛擬機裡確實是多了一個線程:

這時這個線程的狀態變化是:1.新建 2.就緒 3.運行。

然後我們在子線程中找到父線程中創建的Handler對象myHandler,然後向它發送一個Message,在這個Message中,可以傳遞任意我們想傳遞的數據,

這裡我沒有什麼好傳的,所以直接new了一個過去。然後myHandler接到這個Message,進入handleMessage方法,在方法裡我對ProgressBar的進度每次加10,

並把它顯示在TextView上,我們可以很明顯地看到TextView的變化,說明UI線程並沒有處於阻塞狀態,界面也沒有假死。最後ProgressBar的進度到了100%,

也就到了這條語句System.out.println("used for breakPoint");當該語句沒有執行時,剛才新建的線程是還存在的,當該語句結束後,也就是該線程的run方法結束後,

這個線程的任務也就完成了,這時它即將進行第5個狀態-死亡。但它不是立即死亡,它將作為一個小垃圾被系統回收。當系統執行完執行相關的內存釋放操作後,

這個線程就自動結束了,我們可以在Debug中看到虛擬機已經找不到這個進程了

,至此該線程死亡。


我通過線程的生命周期來講解了一下Handle的用法,如果你認為我表達的意思中有錯誤的觀點或者有任何疑問,都歡迎給我留言,謝謝指點。

Copyright © Linux教程網 All Rights Reserved