1.在ActivityThread的main方法中开启主线程的消息循环

在其它线程中创建Looper可使用 Looper.prepare()方法

//ActivityThread#main
public static void main(String[] args) {......//将当前线程初始化为looper,将其标记为应用程序的主循环。Looper.prepareMainLooper();
.......//让Looper工作处理消息,开始消息循环Looper.loop();
.......
}

2.创建UI线程Looper

在创建Looper的同时,创建MessageQueue,绑定当前线程,并将Looper放入ThreadLocal进行线程分离,每个线程将调用自己的Looper进行使用。

//Looper
public final class Looper {//装载不同线程Looper的容器static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//应用程序的主循环器,它位于应用程序的主线程中private static Looper sMainLooper;  //与此Looper关联的消息队列final MessageQueue mQueue;//与此Looper关联的线程
final Thread mThread;//Looper构造方法  创建消息队列,获取当前线程
private Looper(boolean quitAllowed) {//创建消息队列   mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}
}//创建主程序Looper
public static void prepareMainLooper() {//创建Looper 主线程传入false参数,禁止退出消息循环(其它线程都为true,可退出)prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}//返回与当前线程关联的Looper对象。如果调用线程未与Looper关联,则返回null。sMainLooper = myLooper();}
}   //创建新Looper,并将其放入ThreadLocal中
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));
}

3.创建MessageQueue

分别创建Java层MessageQueue和native层的MessageQueue

//MessageQueue
public final class MessageQueue {//是否可以退出消息队列private final boolean mQuitAllowed;//当前looper待处理的消息Message mMessages;private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();private IdleHandler[] mPendingIdleHandlers;MessageQueue(boolean quitAllowed) {mQuitAllowed = quitAllowed;//创建native层的MessageQueue mPtr = nativeInit();}
}//android_os_MessageQueue.cpp#android_os_MessageQueue_nativeInit
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();if (!nativeMessageQueue) {jniThrowRuntimeException(env, "Unable to allocate native queue");return 0;}nativeMessageQueue->incStrong(env);return reinterpret_cast<jlong>(nativeMessageQueue);
}//android_os_MessageQueue.cpp#NativeMessageQueue
//Native Looper调用静态方法getForThread(),获取当前线程中的Looper对象。如果为空,则创建Native Looper对象
NativeMessageQueue::NativeMessageQueue() :mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {       mLooper = Looper::getForThread();if (mLooper == NULL) {mLooper = new Looper(false);Looper::setForThread(mLooper);}
}

4.Looper.loop()开启循环

//Looper
public static void loop() {//在ThreadLocal中获取当前线程的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;
......//死循环for (;;) {// //获取MessageQuene消息队列的消息.Message msg = queue.next(); if (msg == null) {//如果没有消息则return,阻塞在这里等待获取Message。return;}
......if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {//msg.target 是Message里的Handler    写入跟踪消息已经开始Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}
......try {//让与Message关联的Handler通过dispatchMessage()处理Message。msg.target.dispatchMessage(msg);dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;} finally {if (traceTag != 0) {//结束Trace.traceEnd(traceTag);}}......//重新循环可能正在使用的消息msg.recycleUnchecked();}
}

5.MessageQueue .next()取出消息

消息的处理会优先处理Native层的消息,其次才处理Java层的消息。
在正常时候,我们发送的Message全都是同步消息,当然我们也可以发送异步消息。
当开启了同步障碍,Looper在获取下一个要执行的消息时,会在链表中寻找第一个要执行的异步消息,如果没有找到异步消息,就让当前线程沉睡。实质上是一个对消息队列的优先级实现。

//MessageQueue
Message next() {final long ptr = mPtr;//如果native层的looper被放弃的时候(调用了quit方法)返回nullif (ptr == 0) {return null;}//-1仅在第一次迭代期间int pendingIdleHandlerCount = -1;int nextPollTimeoutMillis = 0;//死循环for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}//阻塞方法,主要是通过native层的epoll监听文件描述符的写入事件来实现的。//如果nextPollTimeoutMillis=-1,一直阻塞不会超时//如果nextPollTimeoutMillis=0,不会阻塞,立即返回。//如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。nativePollOnce(ptr, nextPollTimeoutMillis);synchronized (this) {//获取系统开机到现在的时间final long now = SystemClock.uptimeMillis();Message prevMsg = null;//msg是最后查找到的消息,这里初始化为消息队列的队头消息Message msg = mMessages;//如果当前开启了同步障碍if (msg != null && msg.target == null) {//msg.target == null表示此消息为消息屏障(通过postSyncBarrier方法发送来的)//处理同步障碍,会循环找出第一个异步消息(同步障碍消息)//所有同步消息都将忽略(平常发送的一般都是同步消息)do {prevMsg = msg;msg = msg.next;// 如果这个消息是同步的,那么继续向下找异步的} while (msg != null && !msg.isAsynchronous());}if (msg != null) {if (now < msg.when) {// 如果当前消息的执行时间没到,让它沉睡到下个消息的执行时间,设置一下阻塞时间nextPollTimeoutMillis//进入下次循环的时候会调用nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞;nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {//正常取出消息,不需要等待时间或者等待时间已经到了,那么直接返回该消息//从消息队列中删除待返回的msg(剪断链表)//设置mBlocked = false代表目前没有阻塞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 {//没有消息,会一直阻塞,直到被唤醒nextPollTimeoutMillis = -1;}// 判断是否已经退出了if (mQuitting) {dispose();return null;}//获取空闲时处理任务的handler 用于发现线程何时阻塞等待更多消息的回调接口。if (pendingIdleHandlerCount < 0&& (mMessages == null || now < mMessages.when)) {pendingIdleHandlerCount = mIdleHandlers.size();}//如果空闲时处理任务的handler个数为0,继续让线程阻塞if (pendingIdleHandlerCount <= 0) {// No idle handlers to run.  Loop and wait some more.mBlocked = true;continue;}//判断当前空闲时处理任务的handler是否是为空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; // release the reference to the handlerboolean keep = false;try {keep = idler.queueIdle();} catch (Throwable t) {Log.wtf(TAG, "IdleHandler threw exception", t);}//如果不保存空闲任务,执行完成后直接删除if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}//重置空闲的handler个数,因为不需要重复执行pendingIdleHandlerCount = 0;      //当执行完空闲的handler的时候,新的native消息可能会进入,所以唤醒Native消息机制层nextPollTimeoutMillis = 0;}
}

文末

欢迎关注我的CSDN,分享Android干货,交流Android技术。
对文章有何见解,或者有何技术问题,都可以在评论区一起留言讨论,我会虔诚为你解答。
最后,如果你想知道更多Android的知识或需要其他资料我这里均免费分享,只需你多多支持我即可哦!

——可以直接点这里可以看到全部资料内容免费打包领取。

应用程序进程(三):创建消息循环相关推荐

  1. 1.1 Windows 程序运行原理(消息循环和响应)

    ************************************************* *   本文由小鸟飞飞整理发表 <samboy@sohu.com> * *   首发网站 ...

  2. 【微信小程序】(三)订阅消息实现

    微信小程序订阅消息指的是用户在你的小程序中进行了一些操作,你的小程序可以在某一个时间点向该用户发送消息,通知用户操作的结果.比如用户想要小程序在某一天通知他去买票,在小程序中授予通知权限之后,小程序在 ...

  3. android应用消息,Android学习笔记(05)——Android应用程序的三种消息提示(通知方式)...

    Android有三种消息提示方式,分别是:状态栏通知.对话框通知和吐西(Toast)通知,下面记录这三种不同方式的用法以及区别: 一.状态栏通知(Notification) 通知用于在状态栏显示消息, ...

  4. Android应用程序进程启动过程

    相关文章 Android系统架构与系统源码目录 Android系统启动流程(一)解析init进程启动过程 Android系统启动流程(二)解析Zygote进程启动过程 Android系统启动流程(三) ...

  5. QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数

    版权声明 请尊重原创作品.转载请保持文章完整性,并以超链接形式注明原始作者"tingsking18"和主站点地址,方便其他朋友提问和指正. QT源码解析(一) QT创建窗口程序.消 ...

  6. Android应用程序线程消息循环模型分析

    出自:http://blog.csdn.net/luoshengyang/article/details/6905587 我们知道,Android应用程序是通过消息来驱动的,即在应用程序的主线程(UI ...

  7. Android应用程序线程消息循环模型分析(5)

      从AsyncTask的实现可以看出,当我们第一次创建一个AsyncTask对象时,首先会执行下面静态初始化代码创建一个线程池sExecutor: private static final Bloc ...

  8. Android应用程序进程启动过程的源代码分析(1)

    Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制:这两个特点都是在进程的初始化过程中实 ...

  9. Android系统中的进程管理:进程的创建

    对于操作系统来说,进程管理是其最重要的职责之一. 考虑到这部分的内容较多,因此会拆分成几篇文章来讲解. 本文是进程管理系统文章的第一篇,会讲解Android系统中的进程创建. 本文适合Android平 ...

最新文章

  1. js中Object类型和Array类型的变量被赋值(复制)给其他变量后,修改被赋值(复制)的新变量的值,会影响原始变量的值,这是为什么呢?
  2. python爬图片 beautifulsoup_【Python爬虫】基于BeautifulSoup的微博图片爬虫
  3. (转) intellij idea部署web项目时的位置(Tomcat)
  4. 服务器无法继续该事务 3400000006 错误原因--JAVA调用SQLSERVER存储过程时过程发生异常内部事务未
  5. 【Siddhi】Siddhi 如何表示布尔 Syntax error in SiddhiQL, mismatched input ‘boolean
  6. 亚马逊出的平板电脑_亚马逊发布新Fire HD 8系列平板电脑,90美元起
  7. 《工业控制网络安全技术与实践》一2.2 分布式控制系统
  8. html跨行使用的属性,HTML表格标记详解4:TD参数中设定跨列跨行属性
  9. 从零基础入门Tensorflow2.0 ----三、9.tf.function
  10. Django | 静态文件处理
  11. 脏读,幻读,不可重复读的区别
  12. 关于Tricomi方程的类型分析与标准型求解
  13. DotNet开发的微商分销系统源码,微信三级分销系统源码
  14. 一个很实用的造数工具—Spawner Data Generator
  15. MultipartFile实现图片上传上传
  16. 数字信号处理专题(1)——DDS函数发生器环路Demo
  17. arduino/Mixly TEMT6000环境光传感器
  18. 怎么释放gpu内存占用
  19. linux malloc错误,如何规避GCC中“尝试使用中毒的malloc / calloc”错误?
  20. 链表:两个链表的第一个重合节点

热门文章

  1. Angular学习个人遇见的问题分享
  2. 6、计算机图形学——着色频率、插值与插值的矫正
  3. java 字符串原子变量,如何在java中提供原子读/写2个变量?
  4. 业余无线电通信_登山与业余无线电的完美结合,便携式电台参加VHF比赛心得体会...
  5. python提供两个对象身份比较操作符什么和什么来测试_python - 第二部分
  6. Fragment 源码解析
  7. Java:字符串类String的功能介绍
  8. 创建MYSQL的储存过程
  9. 体绘制(Volume Rendering)概述之4:光线投射算法(Ray Casting)实现流程和代码(基于CPU的实现)...
  10. Solaris10下NDOUtils的安装