实际上关于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. python(八)内置模块logging/os/time/sys/json/pickle

    模块 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护.为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少 ...

  2. 微信小程序注册app

    App() App() 函数用来注册一个小程序.接受一个 object 参数,其指定小程序的生命周期函数等. object参数说明 onLaunch   Function 生命周期函数--监听小程序初 ...

  3. 【树莓派】使用树莓派制作img镜像(一)

    最近一直在折腾树莓派,前几天装了10台设备,最近又来了15台开发板子.基本每台设备都需要进行如下操作: 1.安装树莓派OS,并配置键盘.时区.语言编码格式等: 2.新增组.用户.配置静态IP地址: 3 ...

  4. IE6兼容性问题及IE6常见bug详细汇总

    转载地址:http://www.jb51.net/css/76894.html 1.IE6怪异解析之padding与border算入宽高 原因:未加文档声明造成非盒模型解析 解决方法:加入文档声明&l ...

  5. Model Binding

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  6. neon指令,注意事项

    1. vbic_s8 (int8x8_t a, int8x8_t b) 是  ~(ai & bi),一开始理解成  (~ai )& bi 导致出错 2.uint8x8_t vqshrn ...

  7. mysql跨数据库操作问题

    跨数据库的操作,如果是命名符合mysql规范的直接database.table,如果不符合规范比如加了 -  等符号需要在数据库上面加`database`.table(不是'database'.tab ...

  8. Centos7 搭建 Keepalived+LVS 备注

    NAT模型需要RealServer gateway设定为,DR模式需要执行 RealServer.sh.需要先安装network-tools. #!/bin/bash#description : st ...

  9. [maven] maven变量

    Maven内置变量说明: $${project.basedir}或{basedir} 项目根目录,即包含pom.xml文件的目录 ${project.version}或${version}表示项目版本 ...

  10. poj1192 最优连通子集(树形dp)

    题目链接:poj1192 最优连通子集 求一棵无向树的最大子树和..类似于求最大子段和的办法,树形dp. dp[i][0]:以i为根,不包括 i 结点的子树最大权 dp[i][1]:以i为根,包括 i ...