原創源碼角度分析Android的消息機制系列(六)——Handler的工作原理
ι 版權聲明:本文為博主原創文章,未經博主允許不得轉載。
先看Handler的定義:
/**
* A Handler allows you to send and process {@link Message} and Runnable
* objects associated with a thread"s {@link MessageQueue}. Each Handler
* instance is associated with a single thread and that thread"s message
* queue. When you create a new Handler, it is bound to the thread /
* message queue of the thread that is creating it -- from that point on,
* it will deliver messages and runnables to that message queue and execute
* them as they come out of the message queue.
*
*
There are two main uses for a Handler: (1) to schedule messages and
* runnables to be executed as some point in the future; and (2) to enqueue
* an action to be performed on a different thread than your own.
* ……….
* */
public class Handler {
……..
}
由源碼中對Handler的定義以及注釋,我們可知,Handler主要就是用來發送和處理消息的。每一個Handler的實例都和一個線程以及該線程的MessageQueue相關聯。Hadnler主要有2個作用:①在未來某個時刻去發送或處理Message或Runnable(post方法)②在另一個線程中去處理消息(send方法)。
再看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時,若創建Handler對象,則會拋出"Can"t create handler inside thread that has not called Looper.prepare"異常。所以,必須要在有Looper的線程中創建Handler,否則,程序將拋出異常。
Handler的工作主要包含消息的發送和接收過程。消息的發送可以通過post的一系列方法以及send的一系列方法來實現。下面來看一系列post方法:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
通過源碼,我們可以知道,post的一系列方法最終還是通過send的一系列方法來實現的。
下面看send的一系列發送消息的源碼:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 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;
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);
}
由源碼可知,Handler發送消息的過程,其實就是向消息隊列中插入了一條消息。
由MessageQueue的工作原理和Looper的工作原理我們可以知道,當MessageQueue中插入了新的消息後,next方法就會返回該消息給Looper,Looper接收到消息並開始處理消息,但最終Looper是通過調用Handler的dispatchMessage方法來處理消息的,即消息最終還是交給了Handler去處理。
下面來看Handler的dispatchMessage方法的源碼,如下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run;
}
首先,判斷了Message的callback是否為null,若不為null,則調用handleCallback方法。
Message中有屬性: /*package*/ Runnable callback; 那麼,message.callback即Handler的post方法所傳遞的Runnable參數。再結合handleCallback方法的源碼可知,handleCallback方法其實就是開啟了一個子線程,去處理post方法。
再看dispatchMessage方法的源碼,若Message的callback為空,則判斷mCallback是否為null,由Handler的源碼:
final Callback mCallback;
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
可知,Callback就是一個介面,而且其中定義了handleMessage方法。由此我們可以聯想到,當需要獲取一個Handler實例時,我們除了可以繼承Handler,重寫handleMessage方法外,我們還可以通過實現Callback 介面,然後實現介面中的handleMessage方法來實現。
接著來看dispatchMessage方法的源碼,若mCallback為null,最後還是調用handleMessage方法來處理消息。
在開發過程中,當用Handler處理消息時,我們一般是需要重寫handleMessage方法的,處理消息的邏輯由我們自己來寫。
※優化mysql資料庫的幾個步驟
※JAVAEE——spring02:使用註解配置spring、sts插件、junit整合測試和aop演示
※小程序解析html標籤wxPrase插件
※aws ec2的iam role深度解析
※OpenStack(企業私有雲)萬里長征第三步——調試成功
TAG:達人科技 |
※Prometheus原理和源碼分析
※Avante Technology發布Emendo Cloud 3D列印文件自動分析和維修服務
※ThreadLocal源碼分析
※Twitter 開源數據分析工具——tinfoleak
※LruCache原理分析
※一個可以動態分析惡意軟體的工具——Kernel Shellcode Loader
※Process-Forest-Window進程日誌分析工具;python版的BloodHound
※HikariCP源碼分析之leakDetectionThreshold及實戰解決Spark/Scala連接池泄漏
※如何拿下Gooligan(一):對Gooligan起源和工作原理的初步分析
※Jdk 動態代理異常處理分析,UndeclaredThrowableException
※TensorFlow 的模型分析工具——TFMA
※被植入惡意代碼的Emotet Downloader細節分析
※卡巴斯基——Energetic Bear/Crouching Yeti APT分析報告
※Bioconductor的DNA甲基化晶元分析流程
※簡單分析 Holochain
※【項目分析】Origin Protocol 愛西歐
※深入 JVM 分析 spring-boot 應用 hibernate-validatorNoClassDefFoundError
※基於Markov Chain Monte Carlo的智能手錶睡眠數據分析
※kafka 源碼分析 3 : Producer
※android permissions分析