Handler:是android消息機制的核心。一個線程可以有多個handler,但是只能有一個Looper和MessageQueue。handler是用來在線程間傳遞消息的。
而handler是發送消息以及傳遞消息的。在UI線程也是主線程,由於主線程會自動創建Looper,所以在子線程中,必須自己創建Looper才能創建Handler。
Handler的消息發送可以是handler.sendMessage()或者是handler.post(Runnable)。其中sendMessage()方法需要實現Handler的handleMessage方法,也就是消息的最終處理。
Looper是運行在創建Handler的那個線程中的。由於可以有多個handler,那麼怎麼知道消息的最終處理是交給那個handler的handleMessage中呢?
由於Message類中有個變量叫做target,message.target對應生成該message的handler,所以放在Looper處理時,就會轉到對應的handleMessage中。
MessageQueue:是消息隊列,但是它的實現是單鏈表,因爲是要刪除和添加,所以單鏈表的實現比較好,MessageQueue是由Looper.prapare()中實現的,其實也是Looper.parpare()方法調用Looper構造函數,由Looper構造函數中生成MessageQueue的。MessageQueue有兩個方法,一個是enqueueMessage(),一個是next(),enqueueMessage()方法是插入Message,next()方法是讀取一個Message,並且刪除這個Message。其中next()方法是個無限循環的方法。
Looper:Looper叫做循環,由於MessageQueue只是用來存儲Message的,而Looper則是用來處理Message的。Looper.loop()方法調用,纔開始真正啓動消息循環系統,在loop()中,會不斷的調用messagequeue的next()方法,直到next()方法返回null則會停止。而next()不會主動自己返回null的,需要調用MessageQueue的quit()方法或者quitSafely()使得MessageQueue中的next()方法返回null,使得loop()方法中斷。
ThreadLocal:不是線程,而是以線程爲作用域的,各個線程之間互不干擾的一個數據存儲類,用來存儲Looper的,其中每個線程都有一個ThreadLocal.Values的變量來存儲ThreadLocal的數據,其中是一個table數組。ThreadLocal的好處在於,1.線程之間互不干擾,否則需要設置一個通過handler查找looper的全局hash表。2.用在線程中的函數調用棧深的時候,需要在線程全程傳遞監聽器,可以在該線程中設置一個ThreadLocal的全局變量。
整個流程是:在一般的Android消息機制中,先在主線程中創建一個handler,由於這個handler是在主線程中創建的,所以對應的主線程中本身存在的Looper,在子線程的耗時操作結束以後,需要將這個數據傳遞給主線程來更新UI,那麼就直接調主線程的handler,通過handler.sendMessage()將消息插入到MessageQueue中,再由Looper來提取該消息,並處理,調用msg.target.dispatchMessage(msg),其中msg.target就是對應的handler,只是這個handler.dispatchMessage()方法是在主線程的Looper中執行的。也就實現了從子線程到主線程的傳遞。其中的MessageQueue和Looper都是主線程的。
以下是handler的實例
其中項目地址爲:點擊打開鏈接
package com.example.simmucheng.handlerdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Button Btn_start_sendmessage=null;
private Button Btn_start_Runable=null;
private Button Btn_from_main_to_thread=null;
private Button Btn_stop=null;
private TextView Tv_showtextview=null;
private Handler ThreadHandler;
Handler handler_main=new Handler();
Handler handler_main_handlemessage=new Handler(){
@Override
public void handleMessage(Message msg) {
// ThreadHandler.sendMessage(msg);
Tv_showtextview.append("sendMessage = "+msg.arg1);
}
};
Runnable MyRunnable=new Runnable() {
@Override
public void run() {
Tv_showtextview.append("\nloading");
handler_main.postDelayed(MyRunnable,1000);
}
};
Handler handler1=new Handler(){
@Override
public void handleMessage(Message msg) {
Tv_showtextview.append("\nheihei");
Toast.makeText(MainActivity.this,"tttttt",Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
new MyThread().start();
Btn_start_Runable.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler_main.post(MyRunnable);
}
});
Btn_start_sendmessage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(){
@Override
public void run() {
Message msg=new Message();
msg.arg1=1;
msg.what=2;
handler1.sendMessage(msg);
}
}.start();
}
});
Btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler_main.removeCallbacks(MyRunnable);
}
});
Btn_from_main_to_thread.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg1=new Message();
msg1.arg1=3;
ThreadHandler.sendMessage(msg1);
}
});
}
private void initView() {
Btn_start_sendmessage= (Button) findViewById(R.id.Start_Handler_sendmessage);
Btn_from_main_to_thread= (Button) findViewById(R.id.from_main_to_thread);
Btn_start_Runable= (Button) findViewById(R.id.Start_Handler_Runable);
Btn_stop= (Button) findViewById(R.id.stop);
Tv_showtextview= (TextView) findViewById(R.id.ShowTextView);
}
class MyThread extends Thread{
@Override
public void run() {
Looper.prepare();
ThreadHandler=new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
msg.arg1+=1000;
Message msg1=handler_main_handlemessage.obtainMessage();
msg1.arg1=msg.arg1;
handler_main_handlemessage.sendMessage(msg1);
// 這個裏面,在sendMessage(message)之後,會標記該message的isInUse=true
//所以要想再次sendMessage該message,需要重新obtainMessage得到新的message,這樣
//得到的message的isInUse會被取消
}
};
Looper.loop();
}
}
}
其中enqueueMessage的局部代碼,顯示會將message標記爲已經加入隊列。所以有的時候不注意會出現in use的錯誤。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
<span style="color:#ff0000;">msg.markInUse();</span>
msg.when = when;
Message p = mMessages;
}
}
/*package*/ boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
/*package*/ void markInUse() {
flags |= FLAG_IN_USE;
}