1. 程式人生 > >Handler(原理)建立一個與執行緒相關的Handler

Handler(原理)建立一個與執行緒相關的Handler

我們通常在Activity中建立的Handler,是與UI執行緒繫結的,這裡說的繫結其實是指,Looper和MessageQueue的繫結,

而這裡的執行緒,也就是Looper和MessageQueue所在的執行緒,也就是說Handler所持有的Looper和MessageQueue是

哪個執行緒的,我們就說,此Handler是與哪個執行緒繫結的。

下面先看一個例子

package com.example.liaoli.handler_demo;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private static final String TAG = "Handler_demo"; private Handler UIHandler = new Handler(){ @Override public void handleMessage
(Message msg) { Log.e(TAG, "UI執行緒:" + Thread.currentThread()); } }; class MyThread extends Thread { public Handler handler ; public Looper looper; public void run(){ Looper.prepare(); looper = Looper.myLooper(); handler = new Handler(){ @Override
public void handleMessage(Message msg) { Log.e(TAG,"當前執行緒:" + Thread.currentThread()); } }; Looper.loop(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyThread mt = new MyThread(); mt.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } mt.handler.sendEmptyMessage(0); UIHandler.sendEmptyMessage(0); } }

執行之後列印的結果是:

09-26 18:10:32.072  30495-30507/com.example.liaoli.handler_demo E/Handler_demo﹕ 當前執行緒:Thread[Thread-170,5,main]
09-26 18:10:32.080  30495-30495/com.example.liaoli.handler_demo E/Handler_demo﹕ UI執行緒:Thread[main,5,main]

以上結果說明 

 @Override
public void handleMessage(Message msg) {
                    Log.e(TAG,"當前執行緒:" + Thread.currentThread());
}
中的程式碼是執行在子執行緒中的,此時我們其實就是建立了一個與子執行緒繫結的Handler例項。

子執行緒的run方法中的

looper = Looper.myLooper();

其實就是在建立一個本子執行緒的Looper 例項,而在建立Looper的時候又會建立MessageQueue,

然後在handler的構造方法中會拿到這兩個例項,從而建立繫結關係。看Handler原始碼

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的myLooper()方法

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");}
    sThreadLocal.set(new Looper(quitAllowed));
}

sThreadLocal
是ThreadLocal類的一個例項,Threadlocal類的作用就是,來實現執行緒的資料共享與分離,

這裡的共享指的是同一個執行緒間的共享,分離指的是不同執行緒件的分離,我們可以將其理解

成一個Map,這個Map的key是我們的執行緒例項,value就是我們存的與此執行緒相關的值,當然

ThreadLocal存取並不需要指定Key,只需要用

public T get()
public void set(T value)
方法來取和存資料,當然必須得先存了在能取到資料。

ThreadLocal會根據執行緒去取或存這個值。也就是說只有同一個執行緒中取出來的值才是同一個值,

其實,簡單理解成Map就好。

這也就能解釋為什麼我們在通常我們在Activity中建立用來更新UI的介面為什麼會執行在UI執行緒中的問題。

這就是因為為我們建立的Handler是與ActivityThread的UI執行緒中Looper繫結的

ActivityThread的main方法中的程式碼片段:

     Looper.prepareMainLooper();
……

……
     Looper.loop();

這就在主(UI)執行緒中,建立了一個Looper,然後我們在Activity(UI執行緒中)中建立了一個Handler,Handler 在建構函式中

就會和這個主執行緒中的Looper繫結。所以此時Handler的

private  Handler  UIHandler = new Handler(){
        @Override
public void handleMessage(Message msg) {
            Log.e(TAG, "UI執行緒:" + Thread.currentThread());
}
    };

public void handleMessage(Message msg)

中的程式碼是執行在UI執行緒中的。

再看

public class MainActivity extends AppCompatActivity {


    private static final String TAG = "Handler_demo";
    private  Handler myHandler;
    class MyThread extends  Thread {
        public  Handler handler ;
        public Looper looper;
        public void run(){
            Looper.prepare();
looper = Looper.myLooper();
handler = new Handler(){
                @Override
public void handleMessage(Message msg) {
                    Log.e(TAG,"當前執行緒:" + Thread.currentThread());
}
            };
Looper.loop();
}
    }

    @Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyThread mt = new MyThread();
mt.start();
        try {
            Thread.sleep(2000);
} catch (InterruptedException e) {
            e.printStackTrace();
}
        mt.handler.sendEmptyMessage(0);
        try {
            Thread.sleep(2000);
} catch (InterruptedException e) {
            e.printStackTrace();
}


        myHandler = new Handler(mt.looper){
            @Override
public void handleMessage(Message msg) {
                Log.e(TAG, "Run IN 執行緒:" + Thread.currentThread());
}
        };
myHandler.sendEmptyMessage(0);
}

}

執行結果

09-26 18:18:44.784    1931-1943/com.example.liaoli.handler_demo E/Handler_demo﹕ 當前執行緒:Thread[Thread-176,5,main]
09-26 18:18:46.784    1931-1943/com.example.liaoli.handler_demo E/Handler_demo﹕ Run IN 執行緒:Thread[Thread-176,5,main]

髮型這兩個Handler的Handler的

public void handleMessage(Message msg)
方法的程式碼是執行在同一個執行緒的,

也就是說 Looper是哪個執行緒的,與之繫結的Handler的

public void handleMessage(Message msg)
方法就執行與哪個執行緒。