網站首頁 編程語言 正文
Handler:發送和接收消息
Looper :輪詢循環消息隊列,一個線程只有一個Looper
Message:消息的實體
MessageQueue:主要是存儲消息和管理消息
創建Looper:
//ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
//此處省略代碼
//初始化Looper和messagQueue
Looper.prepareMainLooper();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//用于循環消息
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
//Looper.java
public static void prepareMainLooper() {
//消息隊列不可以quit
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
prepare有兩個重載的方法,主要是看prepare(boolean quitAllowed) 作用是在創建出MessageQueue時后標識消息隊列是否可以被銷毀,
但是在主線程中時不會被銷毀的
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//quitAllowed
//sThreadLocal.get()不為空表示已經創建出Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
//每個線程只能創建出一個Looper
}
//這個地方就是創建出Looper,并且存放到sThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}
MessageQueue創建以及如何綁定Looper
private Looper(boolean quitAllowed) {
//創建MessageQueue
mQueue = new MessageQueue(quitAllowed);
//與當前的線程進行綁定
mThread = Thread.currentThread();
}
MessageQueue(boolean quitAllowed) {
//quitAllowed表示是隊列是否可以被銷毀,主線程的隊列不可以被銷毀需要傳入false
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
Looper.looop()
public static void loop() {
final Looper me = myLooper();//從sThreadLocal中獲取到創建出的looper對象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
boolean slowDeliveryDetected = false;
for (;;) {
//死循環表示會一直去查詢消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
// 隊列里面沒有消息,需要等待MessageQueue發送消息
return;
}
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
//查詢到消息后,然后會去回調到Handler中的dispatchMessage中
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//后面代碼省略......
}
創建handler
//常見的Hanlder的創建方式
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
public Handler(@Nullable Callback callback, boolean async) {
//獲取Looper,這個是從sThreadLocal中獲取到的
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//創建出消息隊列MessageQueue
mQueue = mLooper.mQueue;
//初始化回調
mCallback = callback;
mAsynchronous = async;
}
Looper.myLooper()
Looper.java
//主要是處理多線程并發的問題
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//獲取對于的Looper對象,必須先要調用prepare()方法進行創建
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
創建Message
Message.java
1. Message message = new Message();
2. Message obtain = Message.obtain();
//使用Message.obtain比直接new出來的Message要好,可以避免多次創建,銷毀message對象優化內存和性能的目的
public static Message obtain() {
//用來同步,保證線程安全
synchronized (sPoolSync) {
//回收和復用Handler
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Message與Handler的綁定
創建Message的時候可以通過Message.obtain(Handler h)這個構造函數去綁定,也可以在Handler enqueueMessage中去綁定,所有發送的Message消息都會調用此方法入隊,所以在創建Message的時候可以不去綁定。
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;//綁定
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler發送消息
Handler發送的消息重載方法很多,但常用的只有兩種。sendMessage(Message)方法通過一系列的重載方法調用如下流程:
//1.入口
handler.sendMessage(Message);
//調用到sendMessage
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
//2.調用sendMessageDelayed
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//3.調用到sendMessageAtTime
public boolean sendMessageAtTime(@NonNull 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);
}
//4.調用到enqueueMessage
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
//5.調用到enqueueMessage
//將消息保存在消息隊列中,最終又Looper取出,交給Handler的dispatchMessage進行處理
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) {
// New head, wake up the event queue if blocked.
//如果此隊列中頭部元素是null(空的隊列,一般是第一次),或者此消息不是延時的消息,則此消息需要被立即處理,
//此時會將這個消息作為新的頭部元素,然后判斷如果Looper獲取消息的線程如果是阻塞狀態則喚醒它,讓它立刻去拿消息處理
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//如果此消息是延時的消息,則將其添加到隊列中,原理就是鏈表的添加新元素,按照when,也就是延遲的時間來插入的,延遲的時間越長,
//越靠后,這樣就得到一條有序的延時消息鏈表,取出消息的時候,延遲時間越小的,就被先獲取了.
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; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {//喚醒線程
nativeWake(mPtr);
}
}
return true;
}
public void dispatchMessage(@NonNull Message msg) {
//callback在Message的構造方法中初始化和使用
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
//最終回調到上層執行handlerMessage方法
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler處理消息
在handlerMessage(Message)方法中,我們就可以拿到Message對象,然后進行處理,整個Handler的流程就結束了
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
//獲取Message,進行處理
super.handleMessage(msg);
}
};
總結
Handler的大致流程如上步驟。 從handler.sendMassge發送消息到消息隊列MessageQueue,然后調用looper調用到自己loop()函數帶動MessageQueue從而去輪詢MessageQueue里面的每個Message,當Message達到了可以執行的時間的時候開始執行,執行后會調用Message綁定的Handler來處理消息。
原文鏈接:https://blog.csdn.net/qq_42989195/article/details/123191045
- 上一篇:Android廣播和消息跨進程通信并返回數據
- 下一篇:純css控制文字顯示隱藏
相關推薦
- 2022-11-24 React?hooks使用方法全面匯總_React
- 2022-05-04 R語言數據類型與相應運算的實現_R語言
- 2022-08-25 Python中如何使用Matplotlib庫繪制圖形_python
- 2022-06-30 python神經網絡MobileNet模型的復現詳解_python
- 2022-06-25 Gitlab-runner+Docker實現自動部署SpringBoot項目_docker
- 2022-06-12 postgreSQL數據庫基本概念教程_PostgreSQL
- 2022-07-03 對比分析BN和dropout在預測和訓練時區別_python
- 2021-12-06 CentOS環境使用NFS遠程目錄掛載過程介紹_Linux
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支