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(){ @Overridepublic 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)方法就執行與哪個執行緒。