你在網上看了不少handler的原理,是否是有迷茫的地方,爲何是那個樣子的?java
老是聽你們侃侃而談,談的內容仍是千篇一概,流程原理說的也是那麼個回事,可是再往深問一點,又啥啥不會。。。android
若是你以爲有必要深深的理解它,記住它,請給我一塊兒看看它是如何實現的緩存
handler是android提供的一個能夠在線程間傳遞消息的機制,主要涉及類有:Looper,MessageQueue,Message; 咱們先從消息對象來看源碼吧bash
不只是一個數據類,還實現了Parcelable接口,並且也包含了一個單鏈表的數據結構,還經過對象池,實現了複用數據結構
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
public int sendingUid = UID_NONE;
public int workSourceUid = UID_NONE;
int flags;
public long when;
Bundle data;
Handler target;
Runnable callback;
Message next;
複製代碼
主要包含一下數據內容異步
對於跨進程使用,則主要涉及輕量級跨進程通訊Messenger機制,有興趣的能夠自行了解,這裏暫時不介紹了ide
池是啥?簡單理解:池是使用過對象進行緩存,須要使用對象時,從緩存拿實例,進行變量從新設置便可;好處就是減小對象的建立,減小內存劇烈波動oop
這裏是池技術相關變量大數據
Message next;
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
private static boolean gCheckRecycle = true;
複製代碼
gCheckRecycle變量這裏不可直接操做能夠經過反射來設置;其值改變方法被hide了並且這個方法只有在L版本一下,纔會改變;另外池的複用主要是這個變量,爲true表示已經使用過的對象ui
/** @hide */
public static void updateCheckRecycle(int targetSdkVersion) {
if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
gCheckRecycle = false;
}
}
複製代碼
池數據使用了單鏈表結構,先入後出的操做邏輯嗎,sPool鏈表頭;池中最大數據爲50個,每次回收對象時,則重置對象的全部相關數據
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
void recycleUnchecked() {
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
複製代碼
從鏈表的表頭拿出數據
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0;
sPoolSize--;
return m;
}
}
return new Message();
}
複製代碼
主要使用了隊列進行消息的排隊,也是單鏈表結構,按照時間遞增排序;仍是用了原生方法進行等待,喚醒操做
是一個符合消費者模式的隊列 相關變量
Message mMessages; // 消息隊列對頭
private boolean mQuitting; // 是否結束
private boolean mBlocked; // 是否被阻塞
複製代碼
入隊操做
入隊前,先檢查狀態
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;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
複製代碼
入隊過程
出隊操做
出隊操做是一個阻塞操做
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1;
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null;
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
複製代碼
大體流程以下
原生對象映射java對象中,實際上是把地址java成員變量中,java方法經過把指針來操做原生對象
這裏mPtr爲原生對象地址
nativeWake方法
nativePollOnce方法
消息的發送,是有Handler發起的,消息的接收也是由handler來處理;其過程經過代理來實現的
主要相關變量
final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
複製代碼
dispatchMessage方法在消息被處理時在Looper類中調用
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
複製代碼
其處理方法的優先級: 消息對象的回調(callback) > 回調(mCallback成員變量) > handleMessage方法(空方法)
Handler靜態建立方法
public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
if (looper == null) throw new NullPointerException("looper must not be null");
if (callback == null) throw new NullPointerException("callback must not be null");
return new Handler(looper, callback, true);
}
public static Handler getMain() {
if (MAIN_THREAD_HANDLER == null) {
MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
}
return MAIN_THREAD_HANDLER;
}
public static Handler mainIfNull(@Nullable Handler handler) {
return handler == null ? getMain() : handler;
}
複製代碼
給定looper的handler,主線程Handler;返回給定handler的非空版本
主要是取出隊列中消息,並分發給handler處理消息
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;
private static Observer sObserver;
final MessageQueue mQueue;
final Thread mThread;
複製代碼
sThreadLocal靜態實例,保存了線程的looper對象
sMainLooper:主線程looper對象
sObserver:監聽消息執行狀態:開始,結束,異常
mQueue:消息排隊隊列
mThread:looper對象相關的線程對象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
複製代碼
構造器是私有方法,提供了靜態方法,來獲取主線成looper對象,當前線程looper對象
啓動要調用靜態loop()方法,此方法不停的從隊列中取出數據,若是數據爲空,則跳出循環
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
..........(省略一些代碼)
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......(省略一些代碼)
if (observer != null) {
token = observer.messageDispatchStarting();
}
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......(省略一些代碼)
msg.recycleUnchecked();
}
}
複製代碼
流程大體以下:
這裏主要分析了線程間通訊的機制;進程間通訊機制依賴Messenger通訊機制;下面對線程間通訊進行一些總結
技術變化都很快,但基礎技術、理論知識永遠都是那些;做者但願在餘後的生活中,對經常使用技術點進行基礎知識分享;若是你以爲文章寫的不錯,請給與關注和點贊;若是文章存在錯誤,也請多多指教!