详细讲解Android中的Message的源码
相信大家对于Android中的Handler是在为熟悉不过了,但是要知道,Handler就其本身而言只是一个壳子,真正在内部起到作用的是Message这个类,对于Message这个类,相信大家也不会陌生,正如大家经常用到的Message.obtain()的方法一样。但是大家又是否知道obtain()方法里面为我们做了哪些操作了,下面我就带领大家进行Message的王国,去一探究竟吧。
首先映入眼帘的是这样的一行代码:
|
1
|
public final class Message implements Parcelable |
不用多说,Message实现了Parcelable的接口,也就是说经过Message封装的数据,可以通过Intent与IPC进行传输。既然实现了Parcelable接口,那么在Message方法中必不可少这三个方法:1)writeToParcel 2)describeContents 3)createFromParcel。
下面我们需要关注的四个成员变量分别是:
1)public int what
2)public int arg1
3)public int arg2
4)public Object obj
我们经常是用到这样的几个参数,但是其真实的含义是否真正的理解呢?只要google的内部的注释才是真正的可靠的。
1)用户定义消息的识别码,以便于系统识别出当前的消息是关于什么的。由于每一个Handle对于自己的消息的识别码都有自己的命名空间。所以我们也就不用担心各个不同的Handler之间会存在冲突的情况。
2)其中第二个参数与第三个参数的意义是一样的,注释上是这样说明的,这两个参数,如果用户只是需要传输简单的int类型的数据,相比较于setData(Bundle bundle),代价更低。
3)第四个参数,按照注释上的说明,是这样理解的:这是一个发送给接受者的一个随意的数据,如果使用Messager来进行发送数据进行跨进程的通信,那么当前的obj如果实现了Parcelable就一定不能够为空指针,对于其他的数据的传输,我们一般使用setData方法就可以了。但是需要注意的是,对于高于android.os.Build.VERSION_CODES#FROYO的版本,这里的Parcelable对象是不支持的。
上面的变量讲完了以后,接下来,我们还需要讲解另外的一组常量的定义:
|
1
2
3
4
5
|
private static final Object sPoolSync = new Object();private static Message sPool;private static int sPoolSize = 0;//池塘里最大的尺寸private static final int MAX_POOL_SIZE = 50; |
乍一看,大家可能不理解上面四个变量的定义,如果我提醒一下大家,Android中的Message是可以重用的,那么相信大家就能够大致猜测到这四个变量的含义了。
1、第一个变量其实就是充当锁的作用,避免多线程争抢资源,导致脏数据
2、sPool这个变量可以理解为消息队列的头部的指针
3、sPoolSize是当前的消息队列的长度
4、定义消息队列缓存消息的最大的长度。
Ok,到这里,Message的成员变量已经讲解完毕,接下来主要是讲解其中的Api方法。
第一个方法就是大家经常用到的obtain方法,而且不带任何的参数:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new CustomMessage(); }www.2cto.com |
首先为了避免多线程进行争抢资源,给sPoolSync进行加锁。首先判断当前的队列的指针是否为空,如果当前的指针已经不为空,当前的队列的头部的消息就是可以重用并且被取出,那么当前的队列的头指针指向当前的消息的下一个消息,也就是m.next,同时把取出的消息的尾部指针置为null,队列的长度减1.
第二个方法:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public static Message obtain(Message orig) { Message m = obtain(); m.what = orig.what; m.arg1 = orig.arg1; m.arg2 = orig.arg2; m.obj = orig.obj; m.replyTo = orig.replyTo; if (orig.data != null) { m.data = new Bundle(orig.data); } m.target = orig.target; m.callback = orig.callback; return m; } |
我们可以看到,这个方法相对于上面的方法多了一个orig的参数,从上面的代码我们可以看到,首先从队列中取出Message的对象,然后对其中的参数的对象的各个数据进行逐一的拷贝,并最终返回对象。
第三个方法如下:
|
1
2
3
4
5
|
public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; } |
不用多说,这个函数中为当前创建的消息指定了一个Handler对象,因为我们知道Handler是Message的最终的目的地。
|
1
2
3
4
5
6
|
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; } |
相对于上面的方法,这里面多了一行m.callback = callback,按照注释上面的说明,当一些消息真正的被执行的时候,callback这个Runnbale方法将会被触发执行的。
接下来有一系列的方法的逻辑是差不多的,我们取其中的一个进行讲解:
|
1
2
3
4
5
6
7
8
|
public static Message obtain(Handler h, int what, int arg1, int arg2) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; return m; } |
也就是说创建一个Message的时候,顺便可以为这个Message提供一些逻辑上需要的参数。
消息有创建,那么就必然存在回收的概念,下面我们一起来看一下:
|
1
2
3
4
5
6
7
8
9
10
|
public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } |
void clearForRecycle() { flags = 0; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; when = 0; target = null; callback = null; data = null; }
|
1
|
|
在clearForRecycle这个函数中,是做一些回收的预处理的操作,该置为0的参数置为0,该置为null的参数置为null。在recycle的函数中,只要当前的缓存的队列的长度没有超过上限,将当前的消息添加到队列的尾部。
下面的方法是关于实现Parcelable所需要的方法:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
public static final Parcelable.Creator<custommessage> CREATOR = new Parcelable.Creator<custommessage>() { public Message createFromParcel(Parcel source) { Message msg = Message.obtain(); msg.readFromParcel(source); return msg; } public Message[] newArray(int size) { return new Message[size]; } }; public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { if (callback != null) { throw new RuntimeException( "Can't marshal callbacks across processes."); } dest.writeInt(what); dest.writeInt(arg1); dest.writeInt(arg2); if (obj != null) { try { Parcelable p = (Parcelable)obj; dest.writeInt(1); dest.writeParcelable(p, flags); } catch (ClassCastException e) { throw new RuntimeException( "Can't marshal non-Parcelable objects across processes."); } } else { dest.writeInt(0); } dest.writeLong(when); dest.writeBundle(data); Messenger.writeMessengerOrNullToParcel(replyTo, dest); } private void readFromParcel(Parcel source) { what = source.readInt(); arg1 = source.readInt(); arg2 = source.readInt(); if (source.readInt() != 0) { obj = source.readParcelable(getClass().getClassLoader()); } when = source.readLong(); data = source.readBundle(); replyTo = Messenger.readMessengerOrNullFromParcel(source); }</custommessage></custommessage> |
Ok,Message的内核源码的剖析就讲解到这里,相信大家以后再用到这个类的时候会有更深的理解啦。
结伴旅游,一个免费的交友网站:www.jieberu.com
推推族,免费得门票,游景区:www.tuituizu.com
详细讲解Android中的Message的源码的更多相关文章
- 详细讲解Android中的AbsListView的源码
不知道各位童鞋们在开发的过程中有没有感兴趣过ListView是如何实现的呢?其实本身ListView的父类AbsListView才是关键,但是如果大家看过源码的话,会发现AbsListView将近70 ...
- android中使用afinal一行源码显示网络图片
下面代码是关于android中使用afinal一行显示网络图片的代码. public class DemoActivity extends FinalActivity { @Override publ ...
- 详细讲解Android的网络通信(HttpUrlConnection和HttpClient)
前言,Android的网络通信的方式有两种:使用Socket或者HTTP,今天这一篇我们详细讲解使用HTTP实现的网络通信,HTTP又包括两种方式编程方式: (1)HttpUrlConnection: ...
- 详细讲解nodejs中使用socket的私聊的方式
详细讲解nodejs中使用socket的私聊的方式 在上一次我使用nodejs+express+socketio+mysql搭建聊天室,这基本上就是从socket.io的官网上的一份教程式复制学习,然 ...
- 详细讲解Android对自己的应用代码进行混淆加密防止反编译
1.查看项目中有没有proguard.cfg. 2.如果没有那就看看这个文件中写的什么吧,看完后将他复制到你的项目中. -optimizationpasses 5 -dontusemixedcasec ...
- 第五节:详细讲解Java中的接口与继承
前言 大家好,给大家带来详细讲解Java中的接口与继承的概述,希望你们喜欢 什么是接口(interface) 接口中的方法都是抽象方法,public权限,全是抽象函数,不能生成对象 interface ...
- 第四节:详细讲解Java中的类和面向对象思想
前言 大家好,给大家带来详细讲解Java中的类和面向对象思想的概述,希望你们喜欢 类和面向对象 在Java中怎样理解对象,创建对象和引用:什么是引用,对于基础学习的同学,要深入了解引用.示例:Stri ...
- 第九节:详细讲解Java中的泛型,多线程,网络编程
前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...
- 第八节:详细讲解Java中的异常处理情况与I/O流的介绍以及类集合框架
前言 大家好,给大家带来详细讲解Java中的异常处理情况与I/O流的介绍以及类集合框架的概述,希望你们喜欢 JAVA 异常 try...catch...finally结构的使用方法 class Tes ...
随机推荐
- python调用jenkinsapi
在通过python 调用jenkinsapi的时候,需要对一些作业进行定时对构建 报错: <title>Error 403 No valid crumb was included in t ...
- Java实现龟兔赛跑
闲极无聊,加上翻手机看到龟兔赛跑的词语,想到了可以通过java起两个线程来实现龟兔赛跑的实现. 代码实现其实很简单: 首先是乌龟类: 然后是兔子类: 最后是赛跑类: 接下里让我们看一下输出结果吧: 乌 ...
- python_操作MySQL 初解
单文件操作数据库 import random import threading, multiprocessing import time, datetime import pymysql import ...
- IDEA怎么关闭暂时不用的工程
一.隐藏 二.隐藏之后显示显示模块 原文地址:https://blog.csdn.net/woshilovetg/article/details/82774437
- JavaSE--面向对象
面向对象(Object Oriented) 面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节:这种思想是将数据作为第一位, ...
- 【测试环境】TCPCopy 使用方法
https://blog.csdn.net/ronmy/article/details/65657691 TCPCopy是一种请求复制(所有基于tcp的packets)工具,可以把在线请求导入到测试系 ...
- Python的is和==区别
字符串比较 1.比较字符串是否相同: ==:比较两个字符串内的value值是否相同 is:比较两个字符串的id值. 以上结果不同 比较数字时不能使用is,结果有时是True,有时是False,is 相 ...
- ELK-全文检索技术-使用总结
一.概念 1.1 基础概念 ELK: 是ElasticSearch,LogStash以及Kibana三个产品的首字母缩写 lucene : apache 的全文搜索引擎工具包 elasticsearc ...
- JSP的9大内置对象和4打作用域对象
一.9大内置对象 二.4大内置作用域对象
- HTTPS加密原理与过程
HTTPS加密原理与过程 HTTP 超文本传输协议一种属于应用层的协议 缺点: 通信使用明文(不加密),内容可能会被窃听 不验证通信方的身份,因此有可能遭遇伪装 无法证明报文的完整性,所以有可能已遭篡 ...