实际上关于activity大概流程已经了解了,在深入的话方向应该是ams的处理操作和界面创建和view绘制。这些话题之后再谈,activity是一个gui程序,其中离不开的就是消息通讯,也就是在消息循环中不断的处理消息,比如用户交互消息,系统提醒消息等。

所以一定要把消息通信作为一个核心的组件,其中涉及到的类有Handler,Looper,Message,MessageQueue,HandlerThread。

首先介绍的就是1.Message了,表示一个消息,关键的几个属性为what:消息的类型。arg1,arg2这个可以传递两个简单的整数。data一个bundle可以传递多个数据。obj可以传递一个对象。when用来表示时间的和消息队列有关,callback是一个runnable也就是说消息除了可以用来传递数据之外还可以处理runnable。这个都是在Handler中做的处理。target就是处理本消息的handler。实际上Message的重点并不是在于这个几个对象的封装,更加关键的是消息队列的链表维护。一直以来都说消息队列是一个链表结构的,但是你看一下MessageQueue并没有使用list或者给是collection。那这个链表到底在哪里?在Jni层?当然jni层实现了一个底层的looper和queue。但是在java层数据结构和操作都是健全的。实际上这个链表结构就是MessageQueue的一个Message对象mMesssages。这真的只是一个消息对象吗?是一个链表。其中的关键就在于Message的一个字段next。

tip:假如熟悉用数据结构,都知道链表的下一个节点的指针维护在本节点中,也就是Message的next实际是维护的下一个Message对象。十分简单的一个实现,

Message有这样一个方法Obtain是获取一个缓冲池中的Message。这个缓冲池是怎么维护的?就是4个static final的对象,sPoolSync是一个锁对象,由于缓冲池可能多线程操作,所以要同步。spool就是一个缓冲池,也是一个Message对象。spoolSize是缓冲池的大小。还有一个代表缓冲池的最大值MAX_POOL_SIZE = 10。也就是当有10个缓冲对象,这些对象实际上就是之前用过的Message对象,为了避免大量的创建,增加复用,减少垃圾回收。缓冲池的原理就是利用一个Message的链表来进行对象缓冲。

tip:所以Message的关键其实在于维护链表,为了更加明白。先说一下缓冲池利用和释放的机制:

synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }

首先spool不为空,就说明有缓冲对象。然后m就是我们要使用的消息,先把spool引用给m。然后把m的next变为null。也就是把刚才的spool从链表中断开。spool = m.next在断开之前把缓冲池的操作根节点向后移了一位。其实都是这个原理,就是链表操作。这个是obtain的获取Message消息。再看一下如何缓冲已废弃的Message

clearForRecycle();

synchronized (sPoolSync) {
           if (sPoolSize < MAX_POOL_SIZE) {
               next = sPool;
               sPool = this;
               sPoolSize++;
           }
       }

这个是Message的recycle函数,clearForRecycle就是把所有数据都置为空,然后当缓冲池没有10的时候,把要缓存的消息,实际就是笨消息实例,next节点变为spool,同时把spool根节点向前移一位,spool = this,容量++。

Message中并没有什么特殊的函数调用,注意sendToTarget这个方法内部是调用target里面的Handler的sendMessage发送给本身处理。假如是new的Message或者是复用的obtain里面的,这个方法不会起作用。

2.Handler:这个是Message的处理器兼职发送器,管理的就是Message的发送和处理,在使用的时候一般是复写Handler的handleMessage方法然后把Handler的对象传递出去发送消息。Handler中会有Looper,MessageQueue,Callback这几个主要的对象,这几个对象会在创建Handler的时候初始化。

消息发送,首先要获取消息,其中基本上都是调用的Message的Obtain的各种重载函数。所以有获取缓冲池中的Message,也可以自己创建。然后就要发送了基本所有的发送都是调用了sendMessqeAtTime,其中调用了MessageQueue的enqueueMessage把消息插入到消息队列中。其中不管Attime还是delayed,delayed就是当前时间+delayed的时间。所以都是调用attime的方法。还有一个sendEmptyMessage,实际上就是从Message缓冲池中去一个对象发送出去。

消息接收和处理:消息的接收实际是looper从MessageQueue中获取了消息之后,交给了Handler的dispatchMessage,在这个函数里首先查看Handler有没有Callback回调,假如有就执行,然后检测Message中有无Callback回调,有就执行。然后会交给HandleMessage,也就是我们复写的方法中执行。这也就是为什么Handler可以执行Message和runnable的原因。注意这些操作是在Looper线程中,假如是UI线程,必须注意执行的时间了。

3Looper:开始看looper的时候,会有人这么说线程一共分两种,一种就是带有Looper的,比如UI线程。一种没有looper假如你要在没有looper的线程中使用Handler就要自己构造looper或者是使用HandlerThread。这个实际上看了流程篇的介绍后就明白了。activity的ui线程实际上在创建的时候就创建了Looper,并且一直进行的消息循环。所有的UI线程的动作都是发消息到Looper中执行的。彻底明白了消息循环,就彻底的领悟了actvity运行的机制,包括生命周期都是在消息循环的规范下的,不能让我们自由的定义程序流程。

每一个线程都只能有一个looper,为什么?从原理角度讲,looper作用是从队列中取消息,队列中一旦出现消息就要取出来,这就使得Looper必须做死循环,这也就是消息循环。那么死循环就会阻塞线程执行。一旦有两个looper,一个运行起来,另一个就没办法执行。从代码角度来看,looper是私有的构造,创建只能靠prepare,而创建出来的会保存到ThreadLocal中,也就是说线程唯一性。

looper循环,从prepare中初始化了之后,就可以执行loop方法了,一旦执行了loop之后就会不断的调用Queue的next方法尝试取消息,一旦取到就会dispatchMessage给各个Handler。处理消息。

tip:looper每个线程只有一个,但是可以有多个Handler,我们的activity都是在同一个线程中运行的,但是可以创建多了Handler,那么不会乱吗?不会这就是为什么每一个Message都有一个target,Message只能由创建他的线程处理。也就是目标targetHandler处理。

这有一个有趣的东西,假如没有target怎么办?这时候就要looper退出了,而且Looper的quit中也确实就是这么定义的,注意的是UI线程的looper是不能退出的,在检测target是否为空的时候,还检测了一个Boolean额变量mQuitAllowed.UI线程中的这个变量为false,所以不可以退出

4.MessageQueue:这个就是消息队列了,这个是和jni交互的类,在jni层也有一队列和loop,我觉得是为了优化消息循环。我们要注意的就是next和enqueueMessager方法了。next是为了获取消息队列的下一个Message,enqueueMessage是为了向队列中添加一个Message。具体的过程就不分析了,实际上就是他维护的Message队列mMessages的增加和删除操作。

5HandlerThread,实际上更加简单就是为我们添加了Looper的线程。有一个回调函数onLooperPrepared这个就是还没有执行loop之前的调用,你可以创建一个Handler。也就是说其实自己也可以做一个有looper的线程,你可以调用Looper.preapre然后在做一切的准备操作,调用Loop方法就进入了阻塞的循环,等待消息到来了。

总体来说Handler机制是很简单的,了解清楚概念之后就很容易了。

activity 和 生命周期: 消息通信的更多相关文章

  1. Activity 和 生命周期: 创建

    了解了整体的android创建流程之后,就分析一下到底这个过程中做了什么? activity创建中开始时由activityStack中的realstartActivityLocked函数中调用了act ...

  2. Android Activity的生命周期详解

    应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应. Activity之间通过Intent进行通信.在Intent 的描述结构中,有两个最 ...

  3. Activity的生命周期和启动模式

    Activity的生命周期分析 典型情况下的生命周期.是指在用户参与的情况下,Activity所经过的生命周期的改变. 异常情况下的生命周期.是指Activity被系统回收或者由于当前设备的Confi ...

  4. Android开发之漫漫长途 Ⅰ——Android系统的创世之初以及Activity的生命周期

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>中的相关知识,再次表示该书 ...

  5. Android开发之Activity的生命周期以及加载模式

    本篇博客就来好好的搞一下Activity的生命周期,如果搞过iOS的小伙伴的话,Activity的生命周期和iOS中ViewController的生命周期非常类似.生命周期,并不难理解.一个人的生命周 ...

  6. Activity的生命周期

    Activity的生命周期 以往我们实现页面间的跳转都是实例化Intent类的对象,但是页面在我们眼前的出现与消失没有我们所看到的那么简单,它有一个复杂的生命周期,一个页面的出现,被覆盖,再次出现,被 ...

  7. 浅谈Android中Activity的生命周期

    引言 我想对于Android开发人员来说,Activity是再熟悉不过了,今天我们就来探讨下Activity的生命周期.熟悉的掌握Activity对于开发健壮的Android应用程序来说至关重要.下面 ...

  8. 每天一点Android干货-Activity的生命周期

    Activity Activity是这样一个程序组件,它为用户提供一个用于任务交互的画面. 一个应用程序通常由多个activity组成,它们彼此保持弱的绑定状态.典型的,当一个activity在一个应 ...

  9. Android中Activity的生命周期

    简介: 这个基本是必问的问题了,说一下你对Activity生命周期的理解,呵呵… onCreate, onStart, onResume, onPause, onStop, onDestroy, on ...

随机推荐

  1. [问题2014S13] 解答

    [问题2014S13]  解答 (1) 先证必要性:若 \(A=LU\) 是 非异阵 \(A\) 的 \(LU\) 分解,则 \(L\) 是主对角元全部等于 1 的下三角阵,\(U\) 是主对角元全部 ...

  2. 从零开始学iPhone开发(4)——使用WebView

    转自 总结关于iPhone中UIWEBVIEW读取本地GBK编码格式html 关于webView读取本地GBK编码的html,尝试了两天,终于成功. 欢喜之余,把感想记下来.一般来说,不成都是人犯错, ...

  3. Selenium Web 自动化 - 项目实战(三)

    Selenium Web 自动化 - 项目实战(三) 2016-08-10 目录 1 关键字驱动概述2 框架更改总览3 框架更改详解  3.1 解析新增页面目录  3.2 解析新增测试用例目录  3. ...

  4. Java 集合 - LinkedList

    一.源码解析 (1). 属性 // 链表长度 transient int size = 0; // 链首和链尾 transient Node<E> first; transient Nod ...

  5. sql语句中left join、inner join中的on与where的区别

    table a(id, type): id     type ---------------------------------- 1      1 2      1 3      2 table b ...

  6. UiAutomator环境搭建及详细操作

    一.环境搭建 1.1 必备条件 JDK SDK(API高于15) Eclipse(安装ADT插件) ANT(用于编译生成的jar) 安装JDK并添加环境变量 1.2 详细步骤 1.安装JDK并添加环境 ...

  7. 协程 & 用户级(内核级)线程 & 切换开销 & 协程与异步回调的差异

    今天先是看到多线程级别的内容,然后又看到协程的内容. 基本的领会是,协程是对异步回调方式的一种变换,同样是在一个线程内,协程通过主动放弃时间片交由其他协程执行来协作,故名协程. 而协程很早就有了,那时 ...

  8. 6个html5页面适配iphone6的技巧

    iphone6及iphone6plus已经出来一段时间了.很多移动端网站,以前写死body为320px的,现在估计也忙着做适配了. 大屏幕手机其实一直有,只是以前大家没怎么重视,移动端的H5页面大部分 ...

  9. 配置spring事务管理的几种方式(声明式事务)

    Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSo ...

  10. 生物信息大数据&数据库(NCBI、EBI、UCSC、TCGA)

    想系统的学习生信数据库可以先看一下北大的公开课,有一章专门讲的数据库与软件: -生物信息学:导论与方法 北大\ 生物信息数据库及软件资源 一个优秀的生信开发者能够解决如下问题: 如何鉴定一个重要的且没 ...