内容简介:Android 的消息机制Handler,是在开发过程中都会用到的,它可以轻松的从子线程切换到主线程,大部分的时候我们将Handler会用在更新UI的操作.那么Handler是如何做到不同线程通信的呢? 如何切换线程的呢?本篇文章带领大家来轻松的实现一个Handler,并深入的去了解Handler的实现原理在讲解之前,我们先来了解一下Handler的工作过程,至于如何使用Handler,这里我就不在复述了,只要做过Android开发我相信大家都会使用.Handler发送消息是通过Looper以及Messag
Android 的消息机制Handler,是在开发过程中都会用到的,它可以轻松的从子线程切换到主线程,大部分的时候我们将Handler会用在更新UI的操作.那么Handler是如何做到不同线程通信的呢? 如何切换线程的呢?本篇文章带领大家来轻松的实现一个Handler,并深入的去了解Handler的实现原理
在讲解之前,我们先来了解一下Handler的工作过程,至于如何使用Handler,这里我就不在复述了,只要做过Android开发我相信大家都会使用.
Handler的工作过程
Handler发送消息是通过Looper以及MessageQueue协同工作的.
Looper的初始化:在应用启动时ActivityThread会创建一个 Looper.prepare() ,并调用 Looper.looper() 方法无限循环等待是否有新的消息.
发送消息:通过Handler的send方法发送消息,会调用 MessageQueue.enqueue() 方法,此时消息(Message)会被加入MessageQueue消息队列中,已知在Looper初始化是, Looper.looper() 一直在监听是否存在新的消息,此时Looper发现有新消息到来,就会处理该消息,最终会调用 Handler.handleMessage() 方法,Looper是运行在创建Handler的线程中的, handleMessage 一定在创建Handler的线程中去执行.
这个过程用图来表示
通过上述简单的解了Handler的工作过程,接下来我们就根据上述过程来实现一个简单的Handler,然后我们在带着问题去看Handler的源码.
手写一个Handler
- 首先创建四个类:Handler、Message、MessageQueue、Looper
我们先实现核心的Looper类:
通过一个静态的ThreadLocal来存储Looper对象, prepare() 方法来初始化looper
//存储Looper
private static final ThreadLocal<Looper> mThreadLooper = new ThreadLocal<>();
//looper中存在一个消息队列
public MessageQueue messageQueue;
public Looper() {
messageQueue = new MessageQueue();
}
/**
* 准备 准备时就是在主线程中准备的
*/
public static void prepare() {
//ThreadLocal 会拿到当前的线程
if (null != mThreadLooper.get()) {
throw new RuntimeException(Thread.currentThread() + ":已经有了looper");
}
mThreadLooper.set(new Looper());
}
然后再写一个获取Looper的静态方法 myLooper() 主要是给Handler调用
/**
* 获得当前线程的looper
*
* @return
*/
public static Looper myLooper() {
return mThreadLooper.get();
}
Looper还有一个核心的方法,就是实现轮询器去查询新的消息,我们知道要通过消息队列MessageQueue来查询是否有新的消息,MessageQueue存储的为Message,我们先来实现Message,Message类为链式结构
public int what;
public Object obj;
//下一个消息
public Message next;
//使用此handler发送的消息,则需要分发到这个handler处理
public Handler target;
public void recyle() {
obj = null;
next = null;
target = null;
}
MessageQueue来存储Message,MessageQueue需要实现两个方法,一个是加入队列 enqueue ,一个是获取尾部的队列 next ,Looper轮询去就是调用 next 方法来获取最新的消息,当next没有最新消息时,处于阻塞状态 wait() ,当有入队 enqueue 操作时,需要通知 next 不用处于阻塞状态了 notify() ,我有新消息了,注意入队和取队需要同步synchronized.
入队操作
/**
* 将消息塞入队列
*
* @param message
*/
public void enqueue(Message message) {
//有入队就有取队 需要同步一下
synchronized (this) {
Message m = mMessage;
if (null == m) {
mMessage = message;
} else {
//循环判断是否在链表尾端
Message per;
do {
per = m;
m = per.next;
} while (null != m);
per.next = message;
}
//通知获取 message解除阻塞
notify();
}
}
取队操作
/**
* 获取消息
*
* @return Message
*/
Message next() {
synchronized (this) {
Message message;
for (; ; ) {
message = this.mMessage;
if (null != message) {
break;
} else {
//等待 阻塞状态
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
mMessage = mMessage.next;
return message;
}
}
MessageQueue我们已经实现了,接下来可以实现Looper的轮询器了,来监听新消息
/**
* 不停的从MessageQueue中取出Message
*/
public static void looper() {
Looper looper = Looper.myLooper();
MessageQueue messageQueue = looper.messageQueue;
for (; ; ) {
//不停的获取message
Message message = messageQueue.next();
if (message == null) {
break;
}
//分发到发送message的handler执行
message.target.handleMessage(message);
}
}
接下来,实现Handler方法,我们在Handler中获取Looper,并通过Looper获取MessageQueue发送消息时加入消息队列.
public class Handler {
private Looper looper;
private MessageQueue messageQueue;
public Handler() {
looper = Looper.myLooper();
//拿到当前线程的消息队列
messageQueue = looper.messageQueue;
}
public void sendMessage(Message message) {
message.target = this;
//将此消息加入消息队列
messageQueue.enqueue(message);
}
public void handleMessage(Message message) {
}
}
整体的消息机制代码,我们已经实现了,接下来模拟一下handler的发送过程,第一步初始化Looper,然后开启Looper轮询器监听消息,Handler发送接收消息
public void testHandler() {
Looper.prepare();//looper 处于准备状态
final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
System.out.println(Thread.currentThread() + " ");
}
};
new Thread(new Runnable() {
@Override
public void run() {
handler.sendMessage(new Message());
}
}).start();
Looper.looper();
}
OK,通过上述手写实现简单的handler,相信读者一定明白了,Handler的核心思想.
Handler源码分析
彻底明白Handler的工作过程后,我们就能很彻底的看懂Handler源码的实现了
还是按照上面,手写Handler的实现来分析Android Handler源码.
Looper源码分析
首先看到,熟悉的成员属性
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
再来看 prepare() 方法的实现,将Looper存储到ThreadLocal中去
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
同样也实现了 myLooper 方法,来提供其他类调用Looper
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Android是如何初始化Looper呢?来看ActivityThread源码的main方法,代码如下,对Looper初始化,并开启了轮询器
public static void main(String[] args) {
.......
Looper.prepareMainLooper();
.....
Looper.loop();
}
prepareMainLooper方法很简单,实际上调用了prepare和myLooper方法
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
轮询器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;
........
//无限循环获取Message
for (;;) {
Message msg = queue.next(); // might block 没有新的消息就不执行
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
//如果存在新消息获取target 就是当前的Handler 然后调用dispatchMessage处理消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.....
}
......
}
再来看Handler的dispatchMessage,实际上就是处理消息
public void dispatchMessage(Message msg) {
//如果message的callback实际上是一个Runnable,就调用run方法
if (msg.callback != null) {
handleCallback(msg);
} else {
//如果Handler设置了回调就调用回调
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//直接调用handleMessage
handleMessage(msg);
}
}
Handler源码分析
主要看handler发送消息的代码,Handler在初始化时,构造函数中,获取了Looper和MessageQueue,
public Handler(Callback callback, boolean async) {
......
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handler中发送消息有好几种,我们只看最简单的一个
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
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) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
上述代码实现还是非常简单的,实际上就是将消息添加到消息队列中.
MessageQueue源码
再来看一下MessageQueue的入队和出队
入队操作代码入下,实际上就是添加到Message单链表的尾部
boolean enqueueMessage(Message msg, long when) {
//判断msg当前的handler是否为空
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; // invariant: p == prev.next 添加最新的消息
prev.next = msg;
}
// 这段代码就是通知 next不用处于阻塞状态了,有新的消息过来了,注意这里并没有用notify()方法,而是使用底层C++的一个方法,想要了解的可以看底层的源码
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
再来看一下next方法,此方法也是Looper.loop()轮询器轮询判断是否有新消息的核心方法
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
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 {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
OK,以上就是整个Handler源码工作的核心代码,至于ThreadLocal,我会单独的一篇文章讲解.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Algorithm Design Manual
Steve S. Skiena / Springer / 1998-8-1 / GBP 53.91
Contents u Techniques u Introduction to Algorithms u Correctness and Efficiency u Correctness u Efficiency u Expressing Algorithms u Keeping Score u The RAM Model of Computatio......一起来看看 《The Algorithm Design Manual》 这本书的介绍吧!