Android中對Handle機制的理解
【參考資料】
眼下來看,以下的幾個網址中的內容質量比較不錯。基本不須要再讀別的網址了。
1、android消息機制一
http://xtfncel.javaeye.com/blog/663517
Android消息機制(一)
一、 角色描寫敘述
1.Looper: 一個線程能夠產生一個Looper對象。由它來管理此線程裏的Message Queue(消息隊列)。
2.Handler: 你能夠構造Handler對象來與Looper溝通。以便push新消息到Message Queue裏;或者接收Looper(從Message Queue取出)所送來的消息。
3. Message Queue(消息隊列):用來存放線程放入的消息。
4.線程:UI thread 通常就是main thread,而Android啟動程序時會替它建立一個Message Queue。
每個線程裏可含有一個Looper對象以及一個MessageQueue數據結構。在你的應用程序裏。能夠定義Handler的子類別來接收Looper所送出的消息。
在你的Android程序裏。新誕生一個線程,或運行 (Thread)時,並不會自己主動建立其Message Loop。
Android裏並沒有Global的Message Queue數據結構,比如,不同APK裏的對象
比如:
線程A的Handler對象能夠傳遞消息給別的線程。讓別的線程B或C等能送消息來給線程A(存於A的Message Queue裏(//怎樣理解?))。線程A的Message Queue裏的訊息,僅僅有線程A所屬的對象能夠處理。
使用mHandler = new EevntHandler(Looper.myLooper()); 可用來構造當前線程的Handler對象;當中。EevntHandler是自已實現的Handler的子類別。
使用mHandler = new EevntHandler(
這樣描寫敘述可能太抽像。以下舉幾個實際的樣例來說明:
二、 舉例
1. 同線程內不同組件間的消息傳遞
Looper類用來管理特定線程內對象之間的消息交換(Message Exchange)。
你的應用程序能夠產生很多個線程。
而一個線程能夠有很多個組件,這些組件之間經常須要互相交換訊息。假設有這樣的須要,您能夠替線程構造一個Looper對象。來擔任訊息交換的管理工作。
Looper對象會建立一個MessageQueue數據結構來存放各對象傳來的消息(包含UI事件或System事件等)。例如以下圖:
每個線程裏可含有一個Looper對象以及一個MessageQueue數據結構。在你的應用程序裏。能夠定義Handler的子類別來接收Looper所送出的消息。
同線程不同組件之間的消息傳遞:
public class Activity1 extends Activity implements OnClickListener{ Button button = null; TextView text = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity1); button = (Button)findViewById(R.id.btn); button.setOnClickListener(this); text = (TextView)findViewById(R.id.content); } public void onClick(View v) { switch (v.getId()) { case R.id.btn: //組件1 Looper looper = Looper.myLooper();//取得當前線程裏的looper MyHandler mHandler = new MyHandler(looper);//構造一個handler使之可與looper通信 //buton等組件能夠由mHandler將消息傳給looper後,再放入messageQueue中,同一時候mHandler也能夠接受來自looper消息 mHandler.removeMessages(0); String msgStr = "主線程不同組件通信:消息來自button"; Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//構造要傳遞的消息 mHandler.sendMessage(m);//發送消息:系統會自己主動調用handleMessage方法來處理消息 break; } } private class MyHandler extends Handler{ public MyHandler(Looper looper){ super(looper); } @Override public void handleMessage(Message msg) {//處理消息 text.setText(msg.obj.toString()); //組件2 } } }
說明:
此程序啟動時,當前線程(即主線程, main thread)已誕生了一個Looper對象。而且有了一個MessageQueue數據結構。
looper = Looper.myLooper ();
調用Looper類別的靜態myLooper()函數。以取得眼下線程裏的Looper對象.
mHandler = new MyHandler (looper);
構造一個MyHandler對象來與Looper溝通。
Activity等對象能夠藉由MyHandler對象來將消息傳給Looper。然後放入MessageQueue裏;MyHandler對象也扮演Listener的角色,可接收Looper對象所送來的消息。
Message m = mHandler.obtainMessage(1, 1, 1, obj);
先構造一個Message對象,並將數據存入對象裏。
mHandler.sendMessage(m);
就透過mHandler對象而將消息m傳給Looper,然後放入MessageQueue裏。
此時。Looper對象看到MessageQueue裏有消息m,就將它廣播出去。mHandler對象接到此訊息時。會呼叫其handleMessage()函數來處理,於是輸出"This my message!"於畫面上。
2、Android消息機制二
http://xtfncel.javaeye.com/blog/663518
Android消息處理機制(二)
角色綜述(回想):
(1)UI thread 通常就是main thread,而Android啟動程序時會替它建立一個MessageQueue。
(2)當然須要一個Looper對象,來管理該MessageQueue。
(3)我們能夠構造Handler對象來push新消息到Message Queue裏;或者接收Looper(從Message Queue取出)所送來的消息。
(4)線程A的Handler對象能夠傳遞給別的線程。讓別的線程B或C等能送訊息來給線程A(存於A的Message Queue裏)。
(5)線程A的Message Queue裏的消息。僅僅有線程A所屬的對象能夠處理。
子線程傳遞消息給主線程 publicclass Activity2extends Activityimplements OnClickListener{ Button button =null; TextView text =null; MyHandler mHandler = null; Thread thread ; @Override protectedvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity1); button = (Button)findViewById(R.id.btn); button.setOnClickListener(this); text = (TextView)findViewById(R.id.content); } publicvoid onClick(View v) { switch (v.getId()) { case R.id.btn: thread =new MyThread(); thread.start(); break; } } privateclass MyHandlerextends Handler{ public MyHandler(Looper looper){ super(looper); } @Override publicvoid handleMessage(Message msg) {//處理消息 text.setText(msg.obj.toString()); } } privateclass MyThreadextends Thread{ @Override publicvoid run() { Looper curLooper = Looper.myLooper(); Looper mainLooper = Looper.getMainLooper(); String msg ; if(curLooper==null){ mHandler =new MyHandler(mainLooper); msg = "curLooper is null"; }else{ mHandler =new MyHandler(curLooper); msg = "This is curLooper"; } mHandler.removeMessages(0); Message m = mHandler.obtainMessage(1, 1, 1, msg); mHandler.sendMessage(m); } } }
說明:
Android會自己主動替主線程建立Message Queue。在這個子線程裏並沒有建立Message Queue。
所以,myLooper值為null。而mainLooper則指向主線程裏的Looper。於是。運行到:
mHandler = new MyHandler (mainLooper);
此mHandler屬於主線程。
mHandler.sendMessage(m);
就將m消息存入到主線程的Message Queue裏。mainLooper看到Message Queue裏有訊息。就會作出處理,於是由主線程運行到mHandler的handleMessage()來處理消息。
3、Android線程間通信的message機制
http://www.javafun.cn/viewthread.php?tid=15174、
在Android以下也有多線程的概念。在C/C++中,子線程能夠是一個函數。一般都是一個帶有循環的函數,來處理某些數據。優先線程僅僅是一個復雜的運算過程,所以可能不須要while循環,運算完畢,函數結束。線程就銷毀。
對於那些須要控制的線程,一般我們都是和相互排斥鎖相互關聯,從而來控制線程的進度,一般我們創建子線程,一種線程是非經常見的,那就是帶有消息循環的線程。
消息循環是一個非常實用的線程方式,以前自己用C在Linux以下實現一個消息循環的機制,往消息隊列裏加入數據。然後異步的等待消息的返回。
當消息隊列為空的時候就會掛起線程,等待新的消息的加入。這是一個非常通用的機制。
在Android,這裏的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper。這個事android的新概念。
我們的主線程(UI線程)就是一個消息循環的線程。針對這樣的消息循環的機制,我們引入一個新的機制Handle。我們有消息循環。就要往消息循環裏面發送對應的消息,自己定義消息一般都會有自己對應的處理,消息的發送和清除。消息的的處理。把這些都封裝在Handle裏面。註意Handle僅僅是針對那些有Looper的線程,無論是UI線程還是子線程,僅僅要你有Looper,我就能夠往你的消息隊列裏面加入東西,並做對應的處理。
可是這裏另一點,就是僅僅要是關於UI相關的東西。就不能放在子線程中,由於子線程是不能操作UI的,僅僅能進行數據、系統等其它非UI的操作。
那麽什麽情況以下我們的子線程才幹看做是一個有Looper的線程呢?我們怎樣得到它Looper的句柄呢?
Looper.myLooper();獲得當前的Looper
Looper.getMainLooper () 獲得UI線程的Lopper
我們看看Handle的初始化函數,假設沒有參數。那麽他就默認使用的是當前的Looper,假設有Looper參數,就是用相應的線程的Looper。
假設一個線程中調用Looper.prepare(),那麽系統就會自己主動的為該線程建立一個消息隊列。然後調用 Looper.loop();之後就進入了消息循環,這個之後就能夠發消息、取消息、和處理消息。
這個怎樣發送消息和怎樣處理消息能夠再其它的線程中通過Handle來做,但前提是我們的Hanle知道這個子線程的Looper,可是你假設不是在子線程執行 Looper.myLooper(),通常是得不到子線程的looper的。
public void run() { synchronized (mLock) { Looper.prepare(); //do something } Looper.loop(); }所以非常多人都是這樣做的:我直接在子線程中新建handle,然後在子線程中發送消息。這種話就失去了我們多線程的意義了。
class myThread extends Thread{ private EHandler mHandler ; public void run() { Looper myLooper, mainLooper; myLooper = Looper.myLooper (); mainLooper = Looper.getMainLooper (); String obj; if (myLooper == null ){ mHandler = new EHandler(mainLooper); obj = "current thread has no looper!" ; } else { mHandler = new EHandler(myLooper); obj = "This is from current thread." ; } mHandler .removeMessages(0); Message m = mHandler .obtainMessage(1, 1, 1, obj); mHandler .sendMessage(m); } }能夠讓其它的線程來控制我們的handle,能夠把 private EHandler mHandler ;放在外面。這樣我們的發消息和處理消息都能夠在外面來定義,這樣添加程序代碼的美觀,結構更加清晰。
對如不論什麽的Handle,裏面必需要重載一個函數
public void handleMessage(Message msg)
這個函數就是我們的消息處理。怎樣處理。這裏全然取決於你。然後通過 obtainMessage和 sendMessage等來生成和發送消息, removeMessages(0)來清除消息隊列。
Google真是太智慧了,這樣的框架的產生,我們寫代碼更加輕松了。
有的時候,我們的子線程想去改變UI了,這個時候千萬不要再子線程中去改動,獲得UI線程的Looper,然後發送消息就可以。
我們看看Goole Music App的源碼。
在MediaPlaybackActivity.java中,我們能夠看一下再OnCreate中的有這種兩句:
mAlbumArtWorker = new Worker("album art worker"); mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());
非常明顯這兩句。是構建了一個子線程。
而且這個子線程還是Looper的子線程,這裏非常牛逼的使用了 mAlbumArtWorker.getLooper()這個函數,由於我們知道,我們可以得到子線程的Looper的途徑僅僅有一個:就是在子線程中調用 Looper.myLooper (),而且這個函數還要在我們perpare之後調用才幹得到正確的Looper,可是他這裏用了一個這種什麽東東 getLooper。不知道它是怎樣實現的?
這裏有一個大概的思路,我們在子線程的的prepare之後調用 myLooper ()這種方法,然後保存在一個成員變量中,這個getLooper就返回這個東西,可是這裏會碰到多線程的一個非常突出的問題,同步。我們在父線程中調用 mAlbumArtWorker.getLooper(),可是想要這個返回正確的looper就必需要求我們的子線程執行了prepare,可是這個東西實在子線程執行的,我們怎樣保證呢?
我們看Google是怎樣實現的?
private class Worker implements Runnable { private final Object mLock = new Object(); private Looper mLooper; /** * Creates a worker thread with the given name. The thread * then runs a [[email protected]][email protected][/email] android.os.Looper}. * @param name A name for the new thread */ Worker(String name) { Thread t = new Thread(null, this, name); t.setPriority(Thread.MIN_PRIORITY); t.start(); synchronized (mLock) { while (mLooper == null) { try { mLock.wait(); } catch (InterruptedException ex) { } } } } public Looper getLooper() { return mLooper; } public void run() { synchronized (mLock) { Looper.prepare(); mLooper = Looper.myLooper(); mLock.notifyAll(); } Looper.loop(); } public void quit() { mLooper.quit(); } }我們知道。一個線程類的構造函數是在主線程中完畢的。所以在我們的 Worker的構造函數中我們創佳一個線程。然後讓這個線程執行,這一這個線程的創建是指定一個 Runnabl,這裏就是我們的Worker本身,在主線程調用 t.start();,這後,我們子線程已經創建,而且開始運行work的run方法。然後以下的代碼非常藝術:
synchronized (mLock) { while (mLooper == null) { try { mLock.wait(); } catch (InterruptedException ex) { } } }
我們開始等待我們的子線程給mLooper賦值,假設不賦值我們就繼續等,然後我們的子線程在執行run方法之後,在給 mLooper賦值之後,通知worker夠著函數中的wait。然後我們的構造函數才幹完畢,所以我們說:
mAlbumArtWorker = new Worker("album art worker");
這句本身就是堵塞的,它創建了一個子線程,開啟了子線程,而且等待子線程給mLooper賦值,賦值完畢之後,這個函數才返回,這樣才幹保證我們的子線程的Looper的獲取絕對是正確的,這個構思非常有創意。
值得借鑒<!--++ plugin_code qcomic begin--> <!--++ plugin_code qcomic end-->
4、Android中Handler的用法-在子線程中更新界面
二、知識要點
一、知識點
1、handler應該由處理消息的線程創建。
2、handler與創建它的線程相關聯,並且也僅僅與創建它的線程相關聯。handler執行在創建它的線程中,所以,假設在handler中進行耗時的操作。會堵塞創建它的線程。
【來源】以上來自:
二、一些知識點
1、Android的線程分為有消息循環的線程和沒有消息循環的線程。有消息循環的線程一般都會有一個Looper。主線程(UI線程)就是一個消息循環的線程。
2、
Looper.myLooper(); //獲得當前的Looper
Looper.getMainLooper () //獲得UI線程的Lopper
3、Handle的初始化函數(構造函數),假設沒有參數。那麽他就默認使用的是當前的Looper,假設有Looper參數,就是用相應的線程的Looper。
4、假設一個線程中調用Looper.prepare(),那麽系統就會自己主動的為該線程建立一個消息隊列。然後調用 Looper.loop();之後就進入了消息循環。這個之後就能夠發消息、取消息、和處理消息。【來源】以上來自:http://www.javafun.cn/viewthread.php?tid=1517
三、應用實例
3.1 handler傳遞message【應用演示樣例一】
package com.android.tutor; import java.util.Timer; import java.util.TimerTask; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; public class HandlerDemo extends Activity { //title為setTitle方法提供變量,這裏為了方便我設置成了int型 private int title = 0; private Handler mHandler = new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case 1: updateTitle(); break; } }; }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Timer timer = new Timer(); timer.scheduleAtFixedRate(new MyTask(), 1, 5000); } private class MyTask extends TimerTask{ @Override public void run() { Message message = new Message(); message.what = 1; mHandler.sendMessage(message); } } public void updateTitle(){ setTitle("Welcome to Mr Wei's blog " + title); title ++; } }上面的代碼,直接在主線程中定義Handler成員。在子線程中通過主線程的handler向主線程發送消息。其使用過程例如以下:
1、在主線程中定義handler,並為這個handler實現handleMessage方法。
2、在子線程中調用主線程的handler。通過其sendMessage方法發送消息。
3.2 handler傳遞runnable對象還有第二種用Handler來進行線程間通信的方式。那就是用Handler來傳遞一個runnable對象。而不是一個message。
【應用實例三】
使用步驟
1、在主線程中定義Handler對象
2、構造一個runnable對象,為該對象實現runnable方法,在該方法中進行一些你想做的耗時操作。
3、在子線程中使用Handler對象post(runnable)對象.
Android中對Handle機制的理解