android Handler脉络整理 (API level 28)

本文详细解析了Android中Handler机制的工作流程,包括Message、Handler、MessageQueue和Looper等关键组件的作用及交互过程。探讨了消息的发送、入队、处理及在子线程中更新UI的多种方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

Handler机制流程以及用到的类:

Handler发送消息的方法:

消息入队列:

取出消息:

消息处理:

在子线程中进行UI操作:

有关Handler的常见面试问题:


Handler机制流程以及用到的类:

  1.Message: 实现 Parcelable,8个obtain(**)方法获得Message实例

  2.Handler:创建Message然后借助Handler发送,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,创建Handler之前要创建Looper对象

  3.MessageQueue:数据结构是一个单向链表,mMessages变量保存链表的第一个元素,Message对象中next字段保存列表的下一个

  4.Looper:死循环从MessageQueue中去除Message,交给相应的Handler处理

Handler发送消息的方法:

post
postAtTime
postDelayed
postAtFrontOfQueue
sendMessage
sendEmptyMessage
sendEmptyMessageDelayed
sendEmptyMessageAtTime
sendMessageDelayed
sendMessageAtTime
sendMessageAtFrontOfQueue
executeOrSendMessage

--------------------------------------> 以上方法全部都走Handler类中 enqueueMessage方法

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

消息入队列:

-> 由上面代码块第6行 走到 MessageQueue的 enqueueMessage  (只展示关键代码)

 boolean enqueueMessage(Message msg, long when) {
        ......
        synchronized (this) {
        ......
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;

            1.取出当前的消息,如果消息等待时间为0或者小于当前消息的等待时间,直接插到当前消息的前面       
            2.如果不是上面的情况:循环遍历已经存在的消息,插入到等待时间 大于前一个并且 小于后一个的位置,排队。 
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                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; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

核心逻辑为:

    1.取出当前的消息,如果消息等待时间为0或者小于当前消息的等待时间,直接插到当前消息的前面       
    2.如果不是上面的情况:循环遍历已经存在的消息,插入到等待时间 大于前一个并且 小于后一个的位置,排队。
 

总之让消息按照等待时间入队列,等待Looper取出

 

取出消息:

关键代码:

queue.next();                                                               //调用的是MessageQueue中的 next() 方法

msg.target.dispathMessage(msg);                             //调用的是Handler中 dispatchMessage 方法

    public static void loop() {
        final Looper me = myLooper();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            ......

            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            ......

            msg.recycleUnchecked();
        }
    }

 下面代码,MessageQueue next() 方法,中的nativePollOnce本地方法,此处发生了阻塞,

与阻塞对应的是唤醒机制在入队的时候enqueueMessage方法。

Java层的阻塞是通过native层的epoll监听文件描述符的写入事件来实现的,阻塞和唤醒都放到了native层

 Message next() {
        ......
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);
            ......
        }
        ......

}

详细的原因请看这篇文章

natvie层的消息阻塞机制和代码

 

消息处理:

调用的是Handler中 dispatchMessage 方法中的

handleCallback    

handleMessage

两个方法

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

在子线程中进行UI操作:

除了正常的发送消息外,还有3个方法在子线程更新UI

1. Handler的post()方法

在java的子线程中,用post方法更新主线程的UI就可以这样写

public class MainActivity extends Activity {
 
	private Handler handler;
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		handler = new Handler();
		new Thread(new Runnable() {
			@Override
			public void run() {
				handler.post(new Runnable() {
					@Override
					public void run() {
						// 在这里进行UI操作
					}
				});
			}
		}).start();
	}
}

2. View的post()方法

public boolean post(Runnable action) {
    Handler handler;
    if (mAttachInfo != null) {
        handler = mAttachInfo.mHandler;
    } else {
        ViewRoot.getRunQueue().post(action);
        return true;
    }
    return handler.post(action);
}

3. Activity的runOnUiThread()方法

public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

 以上的三个方法都是调用了 handler的post方法实现了UI的更新,和 Handler的handleMessage没什么区别,只有视觉和思维上的区别

有关Handler的常见面试问题:

1. handler的 sendMessage post 最终走的是什么方法?  最终走到了MessageQueue的 enqueueMessage(msg, when)方法。

2. 发送delay消息的时候,消息是存储到哪里,是如何运行的? 存储到了MessageQueue中,利用等待时间在native层中阻塞取出

3.线程之间的交互的原理是什么?未知请给出合适答案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值