Android的Handler消息机制 解析

Android的Handler消息机制

实现原理

  1. 主线程会自动调用Looper.prepareMainLooper和Looper.loop,具体是在ActivityThread中main方法中调用的。
public static void main(String[] args) {
    ......省略无关代码
    
    // 主线程的Looper相关准备工作
    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    // 生成主线程
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    
    // 拿到主线程的Handler,并将主线程的Looper绑定到Handler中
    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.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
  1. 子线程使用Handler时,首先需要调用Looper.prepare,prepare方法中,new一个Looper对象,存入ThreadLocal;在Looper的构造中,会new一个MessageQueue,绑定到当前Looper中。
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // new一个Looper对象
    sThreadLocal.set(new Looper(quitAllowed));
}

private Looper(boolean quitAllowed) {
    // new一个MessageQueue,绑定到Looper中
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
  1. 创建Handler实例,在Handler构造中,若传入Looper,则将传入的Looper绑定给Handler的Looper,并将传入Looper的MessageQueue也绑定给Handler的MessageQueue。若不传入Looper,则构造中,直接取当前线程的Looper以及该Looper的MessageQueue和handler绑定。
// 创建Handler选择无参构造,会走到这里
public Handler(Callback callback, boolean async) {
    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 " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    // 拿到当前线程Looper的MessageQueue,绑定到Handler中
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

// 创建Handler选择有参构造,会走到这里
public Handler(Looper looper, Callback callback, boolean async) {
    // 将传入的Looper以及该Looper的MessageQueue绑定到Handler中,让Handler在Looper所在的线程环境中
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
  1. 接着调用Looper.loop,拿到myLooper,也就是从ThreadLocal中取,在拿到myLooper的MessageQueue,对MessageQueue死循环,MessageQueue.next()获取消息,没有消息则挂载。有消息时,会调用message的target的dispatchMessage方法分发消息。dispatchMessage方法中,首先判断message是否有回调,有则直接将新消息传递给回调接口的run方法中。若message没有回调,则再判断handler是否有回调,有回调,则将新消息传递给回调接口的handleMessage方法中。若handler也没有回调,则将消息传递给handler的handleMessage公开方法中。外部重写该方法即可接收处理新消息。
public static void loop() {
    // 拿到Looper
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    // 拿到Looper的MessageQueue
    final MessageQueue queue = me.mQueue;

    ......省略无关代码
    
    // 对MessageQueue死循环
    for (;;) {
        // MessageQueue.next()获取消息
        Message msg = queue.next(); // might block
        // 没有消息则挂载
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        ......省略无关代码
        
        try {
            // 有消息时,调用message的target的dispatchMessage方法分发消息
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        
        ......省略无关代码
        
        msg.recycleUnchecked();
    }
}

// Handler分发消息
public void dispatchMessage(Message msg) {
    // Message有回调,则直接将新消息传递给回调接口的run方法中
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        // Handler有回调,则将新消息传递给回调接口的handleMessage方法中
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 将消息传递给handler的handleMessage公开方法中
        handleMessage(msg);
    }
}
  1. hander.sendMessage,会调用enqueueMessage方法,将当前handler赋值给Message的target,然后调用handler的MessageQueue的enqueueMessage方法,内部会将新的message添加进MessageQueue中。此时,Looper中MessageQueue会被唤醒,循环获取到新消息做下一步处理。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    // 将当前handler赋值给Message的target
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    // 调用MessageQueue的enqueueMessage方法,内部会将新的message添加进MessageQueue链表中
    return queue.enqueueMessage(msg, uptimeMillis);
}

相关概念

  • 一个线程对应一个Looper,一个Looper对应一个MessageQueue,一个Looper可对应多个Handler,一个Handler对应一个Looper。
  • 主线程中,MessageQueue死循环,并不会卡死UI。在ActivityThread的main方法中,首先调用Looper.prepareMainLooper,紧接着就会new一个ActivityThread,并且拿到该主线程的mainThreadHandler,再调用Looper的loop开启消息循环。以后UI线程的UI刷新等操作也是在mainThreadHandler发消息执行的。
    原文作者:Yuanchao_子轩
    原文地址: https://www.jianshu.com/p/c91c92b59375
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞