内容简介: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,我会单独的一篇文章讲解.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML 压缩/解压工具
在线压缩/解压 HTML 代码
在线进制转换器
各进制数互转换器