实际上关于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. Spark 1.1.0 安装测试 (分布式 Yarn-cluster模式)

    Spark版本:spark-1.1.0-bin-hadoop2.4 (下载:http://spark.apache.org/downloads.html) 服务器环境的情况,请参考上篇博文 hbase ...

  2. python 学习笔记九 队列,异步IO

    queue (队列) 队列是为线程安全使用的. 1.先入先出 import queue #测试定义类传入队列 class Foo(object): def __init__(self,n): self ...

  3. URLClassLoader类

    URLClassLoader类 1.URLClassLoader类也是ClassLoader类的实现类,它的功能非常强大,他可以从本地文件系统中获取二进制文本来加载类,也可以从远程主机获取二进制文件来 ...

  4. [问题2015S04] 复旦高等代数 II(14级)每周一题(第五教学周)

    [问题2015S04] 设 \(A\) 为 \(n\) 阶方阵, \(C\) 为 \(k\times n\) 矩阵, 且对任意的 \(\lambda\in\mathbb{C}\), \(\begin{ ...

  5. implicit operator

    class Digit { public Digit(double d) { val = d; } public double val; // ...other members // User-def ...

  6. Java线程中yield与join方法的区别

    长期以来,多线程问题颇为受到面试官的青睐.虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用.之前,我讨论了一个w ...

  7. nginx 负载均衡策略

    nginx 负载均衡策略   1. 轮询轮询方式是nginx负载均衡的默认策略,根据每个server的权重值来轮流发送请求,例如:upstream backend {server backend1.e ...

  8. 解决:“java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut myMethod”问题!

    Spring版本:2.5.6 AspectJ是Spring自带的lib. Jdk版本:1.7.0_17 在配置没问题的情况下,报:java.lang.IllegalArgumentException: ...

  9. UIDatePicker的用法

    目录[-] 1.Locale 2.Calendar 3.timeZone 4.date 5.minimumDate 6.maximumDate 7.countDownDuration 8.minute ...

  10. google高级搜索

    ext:php program_listing intitle:MythWeb.Program.Listing inurl:preferences.ini “[emule]” intitle:”Ind ...