消息機(jī)制存在的意義
- 為什么不能在非UI線程中操作UI控件?
因?yàn)锳ndroid的UI控件不是線程安全的,如果在多線程中并發(fā)訪問(wèn)可能會(huì)導(dǎo)致UI控件處于不可預(yù)期的狀態(tài), - 為什么不對(duì)UI控件加上鎖機(jī)制?
首先加上鎖會(huì)讓UI訪問(wèn)的邏輯變得復(fù)雜;其次鎖機(jī)制會(huì)降低UI訪問(wèn)的效率,因?yàn)殒i機(jī)制會(huì)阻塞某些線程的執(zhí)行 - Android是在哪兒校驗(yàn)UI操作是否是在UI線程?
//ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
... ...
mThread = Thread.currentThread();
... ...
}
//該方法會(huì)多個(gè)方法的開(kāi)頭被調(diào)用,例如requestLayout()、invalidateChildInParent()等等... ...
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");
}
}
消息機(jī)制原理
Android系統(tǒng)主要通過(guò)Message、MessageQueue、Looper、Handler三個(gè)類來(lái)實(shí)現(xiàn)消息處理,其中Message代表消息,MessageQueue是用來(lái)描述消息隊(duì)列,Looper是用來(lái)創(chuàng)建消息隊(duì)列以及進(jìn)入消息循環(huán),Handler 是用來(lái)發(fā)送消息和處理消息。(以下源碼均來(lái)自API 26 Android 8.0,源碼在線查看:http://androidxref.com),先看下整個(gè)事件的整體脈絡(luò),建議根據(jù)圖然后去找對(duì)應(yīng)的函數(shù)調(diào)用。大圖點(diǎn)擊

Handler.jpg
Handler
- Handler的成員變量
//可能造成內(nèi)存泄露
private static final boolean FIND_POTENTIAL_LEAKS = false;
//是否為異步,默認(rèn)為false
final boolean mAsynchronous;
final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
- Handler的創(chuàng)建和獲取
public Handler() { this(null, false); }
public Handler(Callback callback, boolean async) {
//檢測(cè)內(nèi)存是否存在內(nèi)存泄露的可能
... ...
mLooper = Looper.myLooper();
if (mLooper == null) {
//必須先執(zhí)行Looper.prepare()的原因
throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
- 消息發(fā)送
//最基本的消息發(fā)送
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); }
public final boolean sendEmptyMessage(int what){ return sendEmptyMessageDelayed(what, 0); }
//延時(shí)發(fā)送消息
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
//SystemClock.uptimeMisllis()是系統(tǒng)啟動(dòng)至今的時(shí)間
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//在未來(lái)某一確定的時(shí)間點(diǎn)發(fā)送消息(發(fā)送消息最終的調(diào)用在這)
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//Message中保存的Handler 對(duì)象
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
- 消息處理
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
// 該Callback實(shí)在初始化的時(shí)候傳進(jìn)來(lái)
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//Handler 的內(nèi)部接口
public interface Callback {
public boolean handleMessage(Message msg);
}
Looper
- Looper的重要成員
//存儲(chǔ)不同線程的Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//主線程的Looper
private static Looper sMainLooper;
final MessageQueue mQueue;
final Thread mThread;
- Looper的創(chuàng)建和獲取
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
//Looper.prepare()只能執(zhí)行一次的原因
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//準(zhǔn)備主線程的Looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//Looper構(gòu)造器
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//拿到當(dāng)前線程的Looper對(duì)象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//拿到主線程的Looper對(duì)象
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
- UI線程中Looper的創(chuàng)建
//ActivityThread.java
public static void main(String[] args) {
... ...
Looper.prepareMainLooper();
... ...
Looper.loop();
... ...
}
- 消息循環(huán)
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
... ...
msg.target.dispatchMessage(msg);
}
}
MessageQueue
- MessageQueue的重要成員
//該MessageQueue是否可退出,通過(guò)Looper.prepare()創(chuàng)建的都是可退出的,UI線程的MessageQueue是不可以退出的
private final boolean mQuitAllowed;
//當(dāng)前消息隊(duì)列的頭部
Message mMessages;
//C++層NativeMessageQueue的地址
private long mPtr;
//是否處于阻塞狀態(tài)
private boolean mBlocked;
- MessageQueue的創(chuàng)建
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
//JNI調(diào)用初始化 C++ 層的 NativeMessageQueue.cpp
mPtr = nativeInit();
}
- 消息入隊(duì)
boolean enqueueMessage(Message msg, long when) {
... ...
synchronized (this) {
... ...
msg.when = when;
Message p = mMessages;
boolean needWake;
//頭部等于空,或者入隊(duì)消息的時(shí)間小于當(dāng)前時(shí)間就插到隊(duì)首
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//尋找隊(duì)尾或者在自己發(fā)送時(shí)間之后的位置,然后插入隊(duì)列中
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) {
//JNI調(diào)用,喚醒NativeMessageQueue
nativeWake(mPtr);
}
}
return true;
}
- 消息出隊(duì)
Message next() {
//執(zhí)行下一條消息時(shí)還需要等待的時(shí)間,當(dāng)為-1時(shí)代表消息隊(duì)列中沒(méi)有消息,則無(wú)限等待
int nextPollTimeoutMillis = 0;
for (;;) {
... ...
//JNI調(diào)用,阻塞操作,當(dāng)?shù)却齨extPollTimeoutMillis時(shí)長(zhǎng),或者消息隊(duì)列被喚醒,都會(huì)返回
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
... ...
if (msg != null) {
if (now < msg.when) {
//當(dāng)異步消息觸發(fā)時(shí)間大于當(dāng)前時(shí)間,則設(shè)置下一次輪詢的超時(shí)時(shí)長(zhǎng)
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;
//成功地獲取MessageQueue中的下一條即將要執(zhí)行的消息
return msg;
}
} else {
//沒(méi)有消息
nextPollTimeoutMillis = -1;
}
//消息正在退出,返回null(調(diào)用了quit()方法)
if (mQuitting) {
dispose();
return null;
}
... ...
}
... ...
}
}
NativeMessageQueu
//Java層中MessageQueue的nativaInit()方法
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
... ...
//將NativeMessageQueue對(duì)象的指針強(qiáng)轉(zhuǎn)為Java中的long類型并返回
return reinterpret_cast<jlong>(nativeMessageQueue);
}
- NativeMessageQueue的構(gòu)造器
//和Java層的MessageQueue的構(gòu)造器很類似
NativeMessageQueue::NativeMessageQueue() : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
//獲取當(dāng)前線程的Looper,類似Java層的myLooper()
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
Looper.cpp
- 構(gòu)造器
Looper::Looper(bool allowNonCallbacks) {
//構(gòu)造一個(gè)喚醒事件的文件描述符,能在用戶態(tài)用做事件wait/notify機(jī)制,通過(guò)內(nèi)核取喚醒用戶態(tài)的事件。
//這個(gè)對(duì)象保存了一個(gè)內(nèi)核維護(hù)的uint64_t類型的整型counter。這個(gè)counter初始值被參數(shù)一指定,一般初值設(shè)置為0。
//read:如果計(jì)數(shù)值counter的值不為0,讀取成功,獲得到該值。如果counter的值為0,非阻塞模式,會(huì)直接返回失敗,并把errno的值指紋EINVAL。
//如果為阻塞模式,一直會(huì)阻塞到counter為非0位置。
//write:會(huì)增加8字節(jié)的整數(shù)在計(jì)數(shù)器counter上,如果counter的值達(dá)到0xfffffffffffffffe時(shí),就會(huì)阻塞。直到counter的值被read。阻塞和非阻塞情況同上面read一樣。
mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
... ...
}
- 喚醒鎖
void Looper::wake() {
uint64_t inc = 1;
//向喚醒事件的文件中寫(xiě)入數(shù)據(jù)
write(mWakeEventFd, &inc, sizeof(uint64_t));
}
- 輪詢
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for(;;){
... ...
if (result != 0) {
... ...
return result;
}
result = pollInner(timeoutMillis);
}
}
int Looper::pollInner(int timeoutMillis) {
... ...
//等待被喚醒,喚醒時(shí)間為timeoutMillis,如果timeoutMillis<0,則等待I/O事件喚醒
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
... ...
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeEventFd) {
if (epollEvents & EPOLLIN) {
awoken(); //已經(jīng)喚醒了,則讀取并清空管道數(shù)據(jù)
}
} else {
... ...
}
... ...
}
... ...
return result;
}
void Looper::awoken() {
uint64_t counter;
//不斷讀取管道數(shù)據(jù),目的就是為了清空管道內(nèi)容
TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
}
疑點(diǎn)
Looper.loop()已經(jīng)進(jìn)入死循環(huán),那么主線程的其他操作是如何執(zhí)行的?
- 首先從線程的角度分析:一個(gè)線程是會(huì)在什么時(shí)間結(jié)束?很明顯是該線程中的代碼執(zhí)行完成后就會(huì)結(jié)束,然后該線程就會(huì)被JVM回收。那么如何保證一個(gè)線程永遠(yuǎn)處于運(yùn)行狀態(tài)?貌似只有死循環(huán)。所以這么設(shè)計(jì)肯定是合理的,不然主線程早已被回收了,之所以一直存在就是因?yàn)長(zhǎng)ooper.loop()一直在執(zhí)行。
- 這時(shí)候第二個(gè)問(wèn)題就出現(xiàn)了,如果Looper.loop()一直在阻塞等待,那么UI的繪制是如何執(zhí)行?那么只能從MainLooper的源頭查起,沒(méi)錯(cuò)就是ActivityThread:
final ApplicationThread mAppThread = new ApplicationThread();
final H mH = new H();
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
//這時(shí)候就是進(jìn)入死循環(huán),一旦退出循環(huán)直接拋出異常
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
//ActivityThread的內(nèi)部類,在這個(gè)類中有許多發(fā)送消息的方法,并且從方法中的參數(shù)可以看出都是與UI線程相關(guān)的操作,并且我們知道Binder的服務(wù)端都是運(yùn)行在Binder線程池中
private class ApplicationThread extends IApplicationThread.Stub {
@Override
public final void scheduleLaunchActivity(... ...) {
... ...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
public final void schedulePauseActivity(... ...) {
... ...
sendMessage(finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY, ... ...);
}
... ...
}
//ActivityThread的內(nèi)部類,該類繼承自Handler,并且處理的消息都是與UI線程相關(guān)
private class H extends Handler {
switch (code) {
case LAUNCH_ACTIVITY:
... ...
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
break;
case PAUSE_ACTIVITY:
handlePauseActivity(... ...);
break;
... ...
}
}
所以根據(jù)以上代碼,可以大致分析出,UI線程本質(zhì)的的所有操作都是有MainHanlder來(lái)進(jìn)行處理,而發(fā)送這些消息的操作就分別在不同的子線程中,例如與生命周期相關(guān)的都是在ApplicationThread的線程中,下面從網(wǎng)上盜了張圖:Android中為什么主線程不會(huì)因?yàn)長(zhǎng)ooper.loop里的死循環(huán)卡死?

image.png
所以說(shuō)主線程不能獨(dú)活,必須依賴于其他線程來(lái)給主線程發(fā)送消息,而我們自己在主線程里面發(fā)送消息無(wú)疑是來(lái)自于另一個(gè)線程先發(fā)的消息,例如我們經(jīng)常會(huì)在Activity的生命周期中進(jìn)行發(fā)送消息,而這些生命周期方法的執(zhí)行也是來(lái)自與另一個(gè)線程的消息,就相當(dāng)于我們?cè)?code>handlerMessage方法中再次發(fā)送消息下面的Demo可以說(shuō)明上述結(jié)論是正確的。
public class MainActivity extends AppCompatActivity {
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
Log.d("TestHandler","Start Thread One");
Looper.prepare();
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d("TestHandler",msg.what+" = "+System.currentTimeMillis());
if (msg.what == 3){
Log.d("TestHandler","send Message!");
sendEmptyMessageDelayed(4,1000);
sendEmptyMessage(5);
}
}
};
Looper.loop();
handler.sendEmptyMessageDelayed(1,500);
handler.sendEmptyMessage(2);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
Log.d("TestHandler","Start Thread Two");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(3);
}
}).start();
}
}
//輸出
03-21 22:21:31.132 21995-22032/? D/TestHandler: Start Thread One
03-21 22:21:31.133 21995-22033/? D/TestHandler: Start Thread Two
03-21 22:21:31.633 21995-22032/? D/TestHandler: 3 = 1521642091633
03-21 22:21:31.633 21995-22032/? D/TestHandler: send Message!
03-21 22:21:31.633 21995-22032/? D/TestHandler: 5 = 1521642091633
03-21 22:21:32.635 21995-22032/com.whf.test D/TestHandler: 4 = 1521642092635?

內(nèi)存泄露問(wèn)題
- 為什么會(huì)發(fā)生內(nèi)存泄露?
- Java 回收機(jī)制是根據(jù)可達(dá)性來(lái)判別,即一個(gè)對(duì)象如果是沒(méi)有被其他對(duì)象引用(即不可達(dá)的),這時(shí)候在GC的過(guò)程就會(huì)把這個(gè)對(duì)象列為可回收的,在下一次的GC的時(shí)候就會(huì)執(zhí)行回收。
- 一個(gè)非靜態(tài)內(nèi)部類會(huì)持有外部類的引用。
- Message對(duì)象的taget屬性引用了Handler對(duì)象。
基于以上三點(diǎn)可知,當(dāng)一個(gè)Activity中有一個(gè)非靜態(tài)的Hanlder類,該Handler類就會(huì)持有該Activity的引用,如果當(dāng)該Activitv退出的時(shí)候,其內(nèi)部的Handler發(fā)送的Message還沒(méi)有被處理完,而這些Message對(duì)象都會(huì)持有該Activity的引用,所以就會(huì)導(dǎo)致Activity無(wú)法被回收,從而造成內(nèi)存泄露。
- Handler如何避免內(nèi)存泄露?
- 以靜態(tài)內(nèi)部類或外部類的形式存在,不要在Activity中寫(xiě)非靜態(tài)的Handler類
- Handler的靜態(tài)內(nèi)部類訪問(wèn)外部類時(shí)采用弱引用
- 在Activity回收前,清空MessageQueue中存儲(chǔ)的該Handler發(fā)送的Message,通過(guò)調(diào)用Handler的
removeCallbackAndMessages()方法,該方法原理如下:
//Handle
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
//MessageQueue
void removeCallbacksAndMessages(Handler h, Object object) {
synchronized (this) {
Message p = mMessages;
while (p != null && p.target == h && (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
HandlerThread
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
IntentService
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
//stopSelf(int)來(lái)保證你當(dāng)前停止Service的請(qǐng)求是基于上一個(gè)請(qǐng)求的。也就是說(shuō),當(dāng)你調(diào)用stopSelf(int),你把startID傳給了對(duì)應(yīng)的要停止的Service,
//這個(gè)startID是上一個(gè)請(qǐng)求的StartID!!如果沒(méi)有第二個(gè)請(qǐng)求來(lái),那么這個(gè)Service就會(huì)死掉,但是如果這個(gè)Service已經(jīng)又接受到一個(gè)新的啟動(dòng)請(qǐng)求之后,
//你才調(diào)用stopSelf(int),那么你傳遞給stopSelf()的ID是上一個(gè)請(qǐng)求的ID,而當(dāng)前Service的startID已經(jīng)更新為新的請(qǐng)求的ID,造成兩個(gè)ID不對(duì)應(yīng),stopSelf()失效,
//那么Service就不會(huì)停止。這樣就避免了將后面的請(qǐng)求終止
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}