理解Android的handler機制--從應用到原理再到實踐
關於Android的多執行緒機制,面試的時候總是問到,今天專門寫這個部落格,目的是把handler說清楚。
分別從下面四個方向說清楚。
由來
問題:為什麼有handler?
我們知道java是支援多執行緒的,而一個APP只有一個UI(即螢幕只有一個),如果每個執行緒都可以更新UI,呵呵,估計我們的APP就亂套了,所以Android的設計者就想著,更新UI只能在主執行緒中,子執行緒是不能更新UI的,子執行緒如果更新UI,系統就會丟擲異常。所以Android就需要提供一種機制,子執行緒通過這種機制可以在主執行緒中更新UI。
那麼java有沒有提供在子執行緒之間實時通訊的機制??? 由於執行緒的特性,一個程序內的所有執行緒夠共享同一儲存空間,即在多執行緒中,執行緒是可以訪問同一記憶體單元,這樣很可能出現數據不同步的問題,因此java提供了 synchronized關鍵字 和 Object 類的wait和notify方法(當然java還提供別的方法),但是此方法對Android更新UI這種特殊場合不是很適用。
因此Android專門提供了非同步訊息處理機制,用來解決在Android子執行緒中更新UI的操作。即handler機制。
應用
handler機制是為了在子執行緒中更新UI的,但是handler的作用不僅僅是為了更新UI的,準確的說是為了非同步訊息處理,因此從以下三種情況說明訊息是如何傳送和接受的。
子執行緒向主執行緒傳送訊息
Android是基於Java的,所以也分主執行緒,子執行緒!
(1)主執行緒:實現業務邏輯、UI繪製更新、各子執行緒串連,類似於將軍;
(2)子執行緒:完成耗時(聯網取資料、SD卡資料載入、後臺長時間執行)操作,類似於小兵;
對於使用者來說,程式碼預設執行在主執行緒中,子執行緒的程式碼在new thread內執行的程式碼。
第一步:在主執行緒中建立一個handler
private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_TEXT: // 在這裡可以進行UI操作 text.setText("Nice to meet you"); break; default: break; } } };
第二步:開啟一個子執行緒,在子執行緒裡直接使用Handler傳送訊息即可
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message); // 將Message物件傳送出去
}
}).start();
主執行緒向子執行緒傳送訊息
分兩種情況:
方法1在子執行緒裡初始化Looper
主執行緒向子執行緒傳送訊息的話,我們需要在子執行緒裡初始化Looper,並在主執行緒裡建立的Handler引用子執行緒的Looper(Handler中引用的是哪個執行緒的Looper,就在哪個執行緒裡處理訊息),下面看程式碼:
//方法1
public void method1(){
thread = new MyThread();
thread.start();//千萬別忘記開啟這個執行緒
delay(1000); //在Handler初始化的時候,thread.looper還沒有初始化,所以加一個延時
handler1 = new Handler(thread.looper){
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE:
// 在這裡可以進行UI操作
Log.d("當前子執行緒是--1--->",Thread.currentThread()+"");
break;
default:
break;
}
};
};
}
//子執行緒
class MyThread extends Thread{
private Looper looper;//取出該子執行緒的Looper
public void run() {
Looper.prepare();//建立該子執行緒的Looper
looper = Looper.myLooper();//取出該子執行緒的Looper
Looper.loop();//只要呼叫了該方法才能不斷迴圈取出訊息
}
}
主執行緒傳送訊息:
//下面是主執行緒傳送訊息
Message message1 = new Message();
message1.what = UPDATE;
handler1.sendMessage(message1);
break;
這種方法有個確定,就是Handler初始化的時候,thread.looper還沒有初始化,會導致Crash。
方法2使用HandlerThread
Android提供了HandlerThread類,子執行緒中有handler,程式碼如下:
//方法2
public void method2(){
//例項化一個特殊的執行緒HandlerThread,必須給其指定一個名字
HandlerThread thread = new HandlerThread("handler thread");
thread.start();//千萬不要忘記開啟這個執行緒
//將mHandler與thread相關聯
handler2 = new Handler(thread.getLooper()){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case UPDATE:
// 在這裡可以進行UI操作
Log.d("當前子執行緒是--2--->",Thread.currentThread()+"");
break;
default:
break;
}
};
};
}
子執行緒向子執行緒傳送訊息
建立子執行緒,該子執行緒接受並處理訊息,(注意,該子執行緒的建立也可以應用上面的情況)
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
childHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SEND:
// 在這裡可以進行UI操作
Log.d(TAG,"這個訊息是從-->>" + msg.obj + "過來的,在" + Thread.currentThread()+ "子執行緒當中執行的");
break;
default:
break;
}
}
};
Looper.loop();//開始輪循
}
}).start();
傳送訊息執行緒:
new Thread(new Runnable() {
@Override
public void run() {
Message msg = childHandler.obtainMessage();
msg.what = SEND;
msg.obj = ""+ Thread.currentThread();
childHandler.sendMessage(msg);
}
}).start();
以上分析主要參考Android使用Handler實現子執行緒與子執行緒、主執行緒之間通訊,但是這偏文章沒有寫好的原始碼,在總結這篇文章的基礎上,實現程式碼並上傳github,可直接下載執行。
原理
原理分析,主要檢視郭霖的《第一行程式碼,第二版》。
java實現
理解了handler機制後,我們可不可以用java手寫一個handler機制呢?