介紹handler之前首先我們來看下ThreadLocal類的用法
private static ThreadLocal<String> sthread;
public static void main(String[] args) {
sthread = new ThreadLocal<>();
sthread.set("這是我的第一個項目");
show();
new Thread(new Runnable() {
@Override
public void run() {
show();
}
});
}
public static void show(){
System.out.println(sthread.get());
}
ThreadLocal就是相當於是一個map集合,他的鍵就是當前的線程,值就是自己設置的值,如果ThreadLocal在主線程中set了值,在子線程中是沒法獲得的,這就是ThreadLocal的一個重要特點,可以將數據和當前線程綁定。
當我們應用開啓的時候系統會調用他的ActivityThread類的Loop.PrepareXXX方法,然後這個方法會調用Loop.prepare()方法。
在這個方法裏面我們把ThreadLocal類的對象所謂Loop的一個成員變量記錄下來,這樣有個好處在於下文handler。或者調用loop.loop()的時候很快的通過ThreadLocal獲取到當前的looper對象。進而獲得MessageQueen。
public final class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
private Printer mLogging;
上面的方法同時是將looper對象綁定到當前線程上面(爲下面的handler的時候回調用sThreadlocal.get()獲得looper)
同時這個方法還把當前looper類的對象與相前線程綁定一起
其實內部就是系統在創建looper對象的prepare()方法的時候同時創建消息隊列MessageQueen,然後把looper對象與當前線程綁定在一起
查看Handler源碼可知
創建Handler對象的時候我們
public Handler() {
this(null, false);
}
然後調用到了
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
你看這個機制多好,首先系統自動的在主線程中創建了looper對象,調用了prepare()方法創建了消息隊列,然後當handler對象一創建的時候調用構造函數,通過ThreadLocal的get()方法獲得當前線程在ThreadLocal中設置的looper引用,然後通過looper對象的引用獲得MessageQueen消息隊列。當Handler對象獲得了消息隊列的引用的時候,
hanlder.sendMessage(msg)底層源碼可知
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
然後調用了
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
然後調用了
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//因爲當前的是handler對象獲得了looper引用,進而獲得了MessageQueen對象的引用,自然能執行這個方法
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
再然後
注意這裏面還有一個注意點就是msg.target=this,也就是將當前的Handler對象引用賦給msg的target屬性、
下面我們看看looper.loop()方法執行了什麼?
接着追了myLooper()
for (;;) {//死循環,會不會把主線程卡死???
不會被卡死。
涉及到Linux下的通訊機制,管道通訊的概念,管道就是內存中的一個特殊的一個文件,這個文件有兩個句柄(其實就是java中的引用),一個是讀的引用,一個是寫的引用,當寫的一端寫入內容時,讀的一端就會被喚醒,讀的一端在沒有讀到消息時會休眠
總結looper.loop()做了什麼?
其實就是首先通過myLooper()方法獲得looper對象引用,然後通過looper對象的引用獲得消息隊列的引用,然後通過一個死循環不斷地從消息隊列中獲取到消息,通過msg.this獲得handler,然後調用handler對象的disPatchmessage()方法執行handMessage()【由我們外部重寫】,這也就消息就循環執行起來了。。。
其實作爲一個對技術熱愛的程序員我們不可能僅僅停留在這裏,試問假如主線程給子線程發消息那我們該如何去做?
由於安卓的主線程比較特殊在應用被開啓的時候就會調用Looper.prepare()方法創建了Looper.MessageQueen,那我們我們子線程如果也想實現主線程給其發消息,那也得手動創建Looper對象,進而獲取到MessageQueen隊列,然後不斷地往裏面發消息。然後通過一個Looper.loop()方法不斷地從裏面取消息,但是這裏有個弊端就是由於Looper.loop()會堵塞住子線程導致子線程沒法結束,所以一般這種方式僅僅用於測試,很少這麼去用。
public class MainActivity extends Activity {
private Handler subHandler;
//1
private Handler mainHandler = new Handler(){
//2
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
Toast.makeText(MainActivity.this, msg.toString(), Toast.LENGTH_SHORT).show();
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//創建一個子線程
Thread subThread = new Thread(new Runnable() {
@Override
public void run() {
//(1)
Looper.prepare();
//(2)
subHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, msg.toString(), Toast.LENGTH_LONG).show();
}
};
Log.d("tag", "我是loop前面的代碼");
//(3)
Looper.loop();//死循環,這樣子線程就一直存在
Log.d("tag", "我是loop後面的代碼");
}
});
subThread.start();
}
//開啓子線程,模擬耗時任務
public void start(View view){
new Thread(new Runnable() {
@Override
public void run() {
//模擬耗時操作
SystemClock.sleep(5000);
Message msg = new Message();
msg.obj = Thread.currentThread().getName();
msg.what = 1;
//3
mainHandler.sendMessage(msg);
}
}).start();
}
//主線程給子線程發送消息
public void send2SubThread(View view){
//發送消息
subHandler.obtainMessage(2, "我是主線程給你發送的數據").sendToTarget();
}
}