Friday, June 11, 2010

android裡的thread的朋友:Handler

android裡的thread
好像不能即時Toast和TextView.setText()
一直出現錯誤訊息(後來找到原因,你往下看就知道了)
只能跟在run()裡執行seekbar.setProgress()

很怪,若要用thread傳送即時訊息更新,好像要用到android的class:handler(花了一天得結果:這個推論沒有錯!但是更新和加總的動作不是副執行緒做,副執行緒只負責sleep(1000),副執行緒永遠不可能可以傳送資料去給主畫面)


Android為了考量安全性和執行效能,不允許副執行緒直接更改主畫面的資料
eoeAndroid網友ardwing在評論中提到:
Android的用戶界面更新不是一個執行緒安全的進程。但有多危險我也不清楚,就是知道不能在子執行緒上進行更新。也就是說一切更新必須黏在和OnCreate()一起的主執行緒上。但對於多工工作來說,特別是開發遊戲引擎上是一個障礙。 為了解決這問題,Android提供了一個處理程序和sendMessage的機制。使設計者可以把主執行緒看成一個用戶界面更新的大本營。而每個子執行緒則變成一個獨立運作、獨立判斷的小個體。這些小個體遇到一些用戶界面更新的需要,便透過 sendMessage向大本營發出更新要求,讓大本營,也就是主執行緒進行排期更新。而在主執行緒負責接收這些信息的地方就是處理器下跟帶(?)的程序。

高煥堂老師在他的教學網站說:
在每一個進程有一個主線程(Main Thread),它的主要任務是處理與UI有關的事件(Event),所以又常稱為UI線程。主線程可以誕生子線程(Child Thread),而且「經 常」需要誕生子線程。其主要原因是:主線程(UI線程)必須時時刻刻(標準為5秒內)去照顧UI的事件,以便快速回應使用者的要求。因此,UI線程沒空閒去執行較為費時的函數(或工作),只好誕生子線程去 執行較為費時的工作了。在Android平台裡,UI線程與其子線程之分工是很明確的:
l   子線程負責執行費時的工作。
l   主線程負責UI的操作或事件;子線程不可以插手有關UI的事。



以下是我寫的mp3播放程式中,想要即時更新已播放時間,
最後找到的辦法:
副執行緒負責每隔一秒傳message,好讓我主畫面去s=s+1

主執行緒:
1.需新增一個Handler
2.此類別需實作handleMessage()方法
protected void onCreate(Bundle savedInstanceState) {
hr = new Handler(){
             public void handleMessage(Message msg) {
                 switch(msg.what){
                 //檢查msg.what若為ABC,就執行s+1,
                 //並將值設成已播放時間
                 case ABC:
                     if(mp.isPlaying()==true){
                     s++;               
                     tv2.setText(convert());
                     }
                 break;
                 }                         
                 super.handleMessage(msg);
             }
        };

}




在跑迴圈的副執行緒:
1.new一個Message類別
2.裡面使用.what函式
3.執行Handler這個物件的sendMessage()方法,括弧裡夾雜Message物件變數
new Thread(new Runnable(){
            public void run(){
               
                while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                //使用Handler和Message把資料丟給主UI去後續處理
                if(Playist.this.isFinishing()==true){
                    return;
                    }
                Message m = new Message();                               
                 m.what = ABC;               
                 Playist.this.hr.sendMessage(m);               
                }                       
            }
        }).start();



幾個原則:
1.副執行緒永遠不可能改變主畫面的內容,如:setText主畫面的TextView
2.副執行緒的功能只是做"時間管理",任何計算或迴圈還是得交回主執行緒去處理

1 comment:

須彌芥子 said...

請問那麼想在dispatchTouchEvent(觸控事件)中使用線程更改bitmap要怎麼做呢?
(一直不停的盪...)