app启动
ActivityThread.main()
Looper.prepareMainLooper()
创建全局唯一的Looper对象
//调用 Looper.prepare(); //实现方法 public static void prepare(){ if(sThreadLocal.get()!=null){ //全局的ThreadLocal中只能存在一个looper对象 return; } sThreadLocal.set(new Looper()); }创建全局唯一的MessageQueue对象
//全局唯一的消息队列 private MessageQueue mQueue; //在looper的构造函数中创建消息队列 private Looper(){ mQueue = new MessageQueue(); }创建Handler
//activity中 Handler handler = new Handler() { //重写该方法 @Override public void handlerMessage(Message message) { super.handlerMessage(message); System.out.println(message.obj.toString()); } };子线程中发送消息
//创建一个子线程 new Thread(new Runnable() { @Override public void run() { LhMessage message=new LhMessage(); message.what=1; message.obj="luhao message test"; //通过handler发送消息 handler.sendMessage(message); } }).start();Handler中的发送方法
private void enqueueMessage(LhMessage message) { //赋值当前消息的handler message.lhHandler = this; //使用messagequeue将消息传入队列中 messageQueue.enqueueMessage(message); }消息队列中将该消息存储起来
//存储一条消息 public void enqueueMessage(LhMessage message) { try { blockingQueue.put(message); } catch (InterruptedException e) { e.printStackTrace(); } }源码中的写法
//activity中发送消息 mHanlder.sendMessage(message); //handler中发送消息 public boolean sendMessage(Message msg,long uptimeMillis){ MessageQueue queue = mQueue; …… return enqueueMessage(queue,,msg,uptimeMillis); } //handler中将消息放入消息队列 private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis){ msg.target = this; …… return queue.enqueueMessage(msg,uptimeMillis); } //messageQueue中将消息存储 boolean enqueueMessage(Message msg,long when){ …… mMessage = msg; …… }发送消息
//ActivityThread.main()方法中 ActivityThread.main(){ Looper.loop(); }Looper.loop()开启消息循环
public static void loop(){ //获得全局的Looper对象 final Looper looper = myLooper(); //获得全局消息变量 final MessageQueue queue = looper.mQueue; …… //开启循环 for(;;){ //从消息队列中不断获取消息 Message msg = queue.next(); …… //调用message中存储的Handler对象的dispatchMessage()方法 msg.target.dispatchMessage(message); …… } …… }Handler中发送消息
public void dispatchMessage(Message msg){ if(){ …… }else{ …… } handlerMessage(msg); } public void handlerMessage(Message message){ //这里是null方法,在activity中的handler中重写后就能够得到回调 }Looper的阻塞主要是靠 MessageQueue来实现的。
在MessageQuese的next()方法中进行阻塞。
在MessageQueue的enqueueMessage()方法中进行唤醒。
主要依赖 native 层的Looper依靠epoll机制进行的。
简单理解阻塞和唤醒
就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。
这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。
底层方法:nativeInit();
android_os_MessageQueue_nativeInit()
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { // 构建MessageQueue NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); if (!nativeMessageQueue) { jniThrowRuntimeException(env, "Unable to allocate native queue"); return 0; } nativeMessageQueue->incStrong(env); //返回到Java层 return reinterpret_cast<jlong>(nativeMessageQueue); }NativeMessageQueue()
NativeMessageQueue::NativeMessageQueue() : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) { //获取该线程关联的Looper mLooper = Looper::getForThread(); if (mLooper == NULL) { // 创建一个Looper对象 mLooper = new Looper(false); // 将该Looper保存到线程的TLS中 Looper::setForThread(mLooper); } }Looper()
Looper::Looper(bool allowNonCallbacks) : mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false), mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { // 构建一个唤醒事件的文件描述符fd mWakeEventFd = eventfd(0, EFD_NONBLOCK); AutoMutex _l(mLock); rebuildEpollLocked();// 重构epoll事件,见2.5 }底层方法:nativePollOnce(ptr,nextPollTimeoutMillis)
MessageQueue.enqueueMessage(Message msg, long when)
boolean enqueueMessage(Message msg, long when) { //消息中的handler不能为null 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"); msg.recycle(); return false; } //将消息设置成使用中 msg.markInUse(); //设置消息延迟时间 msg.when = when; //赋值全局最顶层的消息 Message p = mMessages; //是否需要唤醒 boolean needWake; //当前消息为null,延迟时间为0,最顶层的消息的还姓时间大于当前消息的延迟时间 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; prev.next = msg; } // 如果需要唤醒,则调用底层方法唤醒 if (needWake) { nativeWake(mPtr); } } return true; }底层方法:nativeWake(mPtr)
延时入队主要指enqueueMessage()消息入列是以上代码对message对象池得重新排序,遵循规则(when从小到大)。
此处for死循环推出情况分两种:
第一种:p==null表示对象池中已经运行到了最后一个,无需再循环。
第二种:碰到下一个消息when小于前一个,立马出循环(不管对象池中所有message是否遍历完),进行从新排序。
mThread是UI线程 ,这里检查当前线程是不是UI线程。
//mThread是UI线程 ,这里检查当前线程是不是UI线程。 void checkThread(){ if(mThread != Thread.currentThread()){ throw new CalledFromWrongThreadException("only the original thread that created a view hierarchy can touch its views."); } }在Activity的生命周期中
onCreate UI处于创建过程,对用户来说界面还不可视。不能算是更新UI,只能说是配置UI,或者是设置UI的属性。ViewRootImpl没被创建,所以这个时候不会调用ViewRootImpl.checkThread()。 onStart 界面可视了。 onResume 界面可以交互了。ViewRootImpl被创建。这个时候去交互界面才算是更新UI。 setContentView 只是建立了View树,并没有进行渲染工作。建立了View树,因此我们可以通过findViewById()来获取到View对象。没有进行渲染视图的工作,也就是没有执行ViewRootImpl.performTransversal()同样View中也不会执行onMeasure() 真正的渲染工作是在onResume之后。 如果直接在onresume中获取View.getHeight()/View.getWidth()得到的结果总是0。过程:在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里。
此时主线程会释放CPU资源进入休眠状态直到下个消息到达或者有事务发生通过往pipe管道写端写入数据来唤醒主线程工作这里采用的epoll机制,是一种IO多路复用机制在Handler构造方法里面new Looper,无法保证保证Looper的唯一性。
只有用Looper.prepare()才能保证唯一性。
具体在Looper.prepare()方法中。
一个线程只绑定一个Looper。
所以在Looper构造方法里面初始化就可以保证MessageQueue是唯一的。
Thread对应一个Looper对应一个MessageQueue。
Looper.loop()方法中
从MessageQueue中拿出Message,并且执行其逻辑
这是在Looper中执行的,所以由looper的线程决定
通过消息的唤醒机制,延时入队排序,将message.when从小到大排列,再去发送消息
有关native层源码可以看这篇博客,很详细