Handler机制的理解

开始文章前先说一些废话吧,本来原先就打算写Handler消息机制了,可惜自己以各种理由拖着,最后只能强逼着自己把这个文章写完,好勒,不啰嗦了,开始正文吧。

概述

Handler是Android提供给我们的一套消息机制,可以用来更新UI,也可以用来进行线程间的消息传递。

Handler的使用想必大家已经熟悉的不能再熟悉了,所以就不在多说。

先简单介绍一下涉及到的几个类:

Message:消息,在线程间进行通信的数据单元

MessageQueue:消息队列,主要功能是向消息池中添加消息和取走消息

Handler:处理消息事件,也将消息添加到消息队列中

Looper:不断循环遍历消息队列,分发给不同消息对应的Handler进行处理

再来一张图,帮我们理解下Handler的运行机制

接下来解释一下这张图:

1.Handler通过sendMessage方法发送消息,并调用enqueueMessage方法将消息加入到消息队列MessageQueue中。

2.Looper通过loop方法循环遍历消息队列,从队列MessageQueue中拿出消息Message,进行唤醒操作,然后调用Message对应的Handler里的dispatchMessage分发消息。

3.在Handler的handlerMessage方法中处理消息,这样就完成了一次消息的发送和处理过程。

Handler的运行机制大家稍微的了解了一下,接下来我们来看一下具体的代码实现,以下代码都是基于Android8.0的。

Message

public final class Message implements Parcelable{
    //用去区分不同的消息
    public int what;
     
    //消息所携带的数据
    public int arg1;
    public int arg2;
    public Object obj;

    //消息所对应的Handler
    Handler target;

    //回调方法
    Runnable callback;

    //下一条Message
    Message next;

    //消息池
    private static Message sPool;
    //消息池的大小
    private static int sPoolSize = 0;
    //消息池最大可以存放消息的个数
    private static final int MAX_POOL_SIZE = 50;

    ...

    //从消息池中取出Message
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool; //拿出消息池的队首消息
                sPool = m.next; //将sPool指向下一个消息
                m.next = null;
                m.flags = 0; 
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    
    ...   

  //回收消息,用于MessageQueue和Looper内部使用 
  void recycleUnchecked() {

        ...

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) { //当消息池存放的消息大于最大消息个数就不在存放了
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

}

Message通过next属性组成了一条单链表的结构,callback这个属性我们使用Handler进行post消息时会被赋值。

我们有时会用Message.obtain()来获取Message,从代码中可以看到从消息池中取出消息,返回给调用者,没有new一个返回给调用者。

MessageQueue

...

//加入到消息队列中
boolean enqueueMessage(Message msg, long when) {
        
   if (msg.target == null) { //msg必须与handler绑定,要不然会抛出异常
            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) { //如果正在退出时,回收msg,加入到消息池

                ...

                msg.recycle(); //recycle方法最终调用的还是recycleUnchecked
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                //p为null(代表MessageQueue没有消息) 或者msg的触发时间是队列中最早的还或者msg是立即要处理的
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; //如果阻塞则进行唤醒
            } else {
                //needWake为ture的情况为阻塞状态并且p.target == null(我们自己发送的消息target是不能为null的,这个应该是系统发送的消息)还有就是msg为异步消息
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                 //将消息按时间顺序插入到msg链表中
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; 
                prev.next = msg;
            }

            
            if (needWake) { 
                nativeWake(mPtr); //调用native层的唤醒操作
            }
        }
        return true;
    }


//获取下一个Message
Message next() {

        final long ptr = mPtr;
        if (ptr == 0) { //当native消息循环已经退出,则直接返回
            return null;
        }

        
        int pendingIdleHandlerCount = -1; // 在第一次循环时pendingIdleHandlerCount才为-1
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
		 //阻塞操作,当nextPollTimeoutMillis=-1时阻塞,当为0时表示不阻塞,当为其他时间表示延时
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {

                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
				//查询异步消息
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous()); //当不在是异步消息时,退出循环
                }

                if (msg != null) {
                    if (now < msg.when) {
                        //当消息触发时间大于当前时间,则设置延时时间
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        //获取一个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 {
                    //没有Message则进行阻塞
                    nextPollTimeoutMillis = -1;
                }

                 if (mQuitting) { //如果正在退出,则处理native层的消息队列,并返回null
                    dispose();
                    return null;
                }
                
                //在第一次循环是并且没有消息或者是一个延时消息
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    //继续循环并阻塞或者延时操作
                    mBlocked = true;
                    continue;
                }
              if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
             //只有第一次循环时,才会被运行
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; 

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            //pendingIdleHandlerCount为0,下次将不再运行
            pendingIdleHandlerCount = 0;
            //当mPendingIdleHandlers操作完成以后,无需阻塞
            nextPollTimeoutMillis = 0;
        }


//移除消息
void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            //循环遍历消息队列,移除连续的符合条件的消息
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

           //再循环遍历剩下的消息,移除符合条件的消息
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }
...

MessageQueue中唤醒的方法是nativeWake(),底层是epoll机制(一种IO多路复用机制),通过往pipe管道写端写入数据来唤醒线程工作。阻塞方法是nativePollOnce()方法,该方法会使线程释放CPU资源进入休眠状态,直到下个消息到达,才会被唤醒。

Looper

    ...

//初始化一个消息队列,并获取当前的线程,quitAllowed表示消息队列是否可以退出
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

public static void prepare() {
        prepare(true);
    }

//将当前的Looper与当前线程绑定,并且一个线程只能绑定一个Looper
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));
    }

...

//初始化应用的主线程Looper
public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

//返回主线程的Looper
public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }


//循序遍历消息队列
public static void loop() {
        final Looper me = myLooper(); //从ThreadLocal中取出当前线程绑定的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();

        for (;;) {
            Message msg = queue.next(); //取出消息队列中的下一条消息
            if (msg == null) {
                 //没有消息则退出
                return;
            }

            ...

            try {
                msg.target.dispatchMessage(msg); //调用msg中的handler分发消息
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            
            msg.recycleUnchecked(); //将msg存放到消息池中
        }
    }

...

Looper的prepareMainLooper在app一开始运行时,就在ActivityThread中被调用了,这也就是我们可以在主线程中直接创建一个Handler而不报错的原因,如果要在自己的线程中使用Looper,就要调用的Looper.prepare方法,将Looper与当前线程绑定。

Handler

...
//Handler构造方法
public Handler(Callback callback, boolean async) {
        //匿名类、内部类或本地类用static进行修饰,要不然会提示警告
        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());
            }
        }

        //获取当前线程的Looper与Handler绑定
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //获取MessageQueue与当前Handler绑定
        mQueue = mLooper.mQueue;
        mCallback = callback; //会调用方法
        mAsynchronous = async; //设置消息是否异步处理
    }

//post消息
public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

//获取callback被赋值的Message
private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
 }

//发送消息
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);
    }

//消息的分发,在Looper中next方法中调用的
public void dispatchMessage(Message msg) {
        if (msg.callback != null) { //调用Message中的callback
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) { //调用Handler中的callback
                    return;
                }
            }
            handleMessage(msg); //调用handleMessage方法
        }
    }

Handler有多个构造方法,最终调用的是Handler(Callback callback, boolean async) 这个构造方法。使用post发送消息时,会调用getPostMessage方法获取一个callback被赋值了的Message,然后调用sendMessageDelayed方法,而sendMessageDelayed最终调用的还是sendMessageAtTime这个方法。我们常用的sendEmptyMessage和sendEmptyMessageDelayed还有sendMessageDelayed方法最终调用的也是sendMessageAtTime这个方法。

ActivityThread

下面这段代码是ActivityThread中Looper被初始化的代码

public static void main(String[] args) {

        ...

        //主线程中初始化Looper
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        //开始Looper循环
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

 

总结

通过对涉及到的源码进行分析,我们可以知道:

1.每个线程中只能有一个Looper

2.每个Looper只有一个MessageQueue

3.Looper和Handler是在同一个线程中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值