博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
详细讲解Android中的Message的源码
阅读量:5034 次
发布时间:2019-06-12

本文共 4700 字,大约阅读时间需要 15 分钟。

相信大家对于Android中的Handler是在为熟悉不过了,但是要知道,Handler就其本身而言只是一个壳子,真正在内部起到作用的是 Message这个类,对于Message这个类,相信大家也不会陌生,正如大家经常用到的Message.obtain()的方法一样。但是大家又是否 知道obtain()方法里面为我们做了哪些操作了,下面我就带领大家进行Message的王国,去一探究竟吧。

       首先映入眼帘的是这样的一行代码:

[java]
  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对象是不支持的。

上面的变量讲完了以后,接下来,我们还需要讲解另外的一组常量的定义:

[java]
  1. private static final Object sPoolSync = new Object();  
  2. private static Message sPool;  
  3. private static int sPoolSize = 0;  
  4. //池塘里最大的尺寸  
  5. private static final int MAX_POOL_SIZE = 50;  

乍一看,大家可能不理解上面四个变量的定义,如果我提醒一下大家,Android中的Message是可以重用的,那么相信大家就能够大致猜测到这四个变量的含义了。

1、第一个变量其实就是充当锁的作用,避免多线程争抢资源,导致脏数据

2、sPool这个变量可以理解为消息队列的头部的指针

3、sPoolSize是当前的消息队列的长度

4、定义消息队列缓存消息的最大的长度。

Ok,到这里,Message的成员变量已经讲解完毕,接下来主要是讲解其中的Api方法。

第一个方法就是大家经常用到的obtain方法,而且不带任何的参数:

[java]
  1. public static Message obtain() {  
  2.         synchronized (sPoolSync) {  
  3.             if (sPool != null) {  
  4.                 Message m = sPool;  
  5.                 sPool = m.next;  
  6.                 m.next = null;  
  7.                 sPoolSize--;  
  8.                 return m;  
  9.             }  
  10.         }  
  11.         return new CustomMessage();  
  12.     }  

首 先为了避免多线程进行争抢资源,给sPoolSync进行加锁。首先判断当前的队列的指针是否为空,如果当前的指针已经不为空,当前的队列的头部的消息就 是可以重用并且被取出,那么当前的队列的头指针指向当前的消息的下一个消息,也就是m.next,同时把取出的消息的尾部指针置为null,队列的长度减 1.

第二个方法:

[java]
  1. public static Message obtain(Message orig) {  
  2.         Message m = obtain();  
  3.         m.what = orig.what;  
  4.         m.arg1 = orig.arg1;  
  5.         m.arg2 = orig.arg2;  
  6.         m.obj = orig.obj;  
  7.         m.replyTo = orig.replyTo;  
  8.         if (orig.data != null) {  
  9.             m.data = new Bundle(orig.data);  
  10.         }  
  11.         m.target = orig.target;  
  12.         m.callback = orig.callback;  
  13.         return m;  
  14.     }  

我们可以看到,这个方法相对于上面的方法多了一个orig的参数,从上面的代码我们可以看到,首先从队列中取出Message的对象,然后对其中的参数的对象的各个数据进行逐一的拷贝,并最终返回对象。

第三个方法如下:

[java]
  1. public static Message obtain(Handler h) {  
  2.         Message m = obtain();  
  3.         m.target = h;  
  4.         return m;  
  5.     }  

不用多说,这个函数中为当前创建的消息指定了一个Handler对象,因为我们知道Handler是Message的最终的目的地。

[java]
  1. public static Message obtain(Handler h, Runnable callback) {  
  2.         Message m = obtain();  
  3.         m.target = h;  
  4.         m.callback = callback;  
  5.         return m;  
  6.     }  

相对于上面的方法,这里面多了一行m.callback = callback,按照注释上面的说明,当一些消息真正的被执行的时候,callback这个Runnbale方法将会被触发执行的。

接下来有一系列的方法的逻辑是差不多的,我们取其中的一个进行讲解:

[java]
  1. public static Message obtain(Handler h, int what, int arg1, int arg2) {  
  2.         Message m = obtain();  
  3.         m.target = h;  
  4.         m.what = what;  
  5.         m.arg1 = arg1;  
  6.         m.arg2 = arg2;  
  7.         return m;  
  8.     }  

也就是说创建一个Message的时候,顺便可以为这个Message提供一些逻辑上需要的参数。

消息有创建,那么就必然存在回收的概念,下面我们一起来看一下:

[java]
  1. public void recycle() {  
  2.         clearForRecycle();  
  3.         synchronized (sPoolSync) {  
  4.             if (sPoolSize < MAX_POOL_SIZE) {  
  5.                 next = sPool;  
  6.                 sPool = this;  
  7.                 sPoolSize++;  
  8.             }  
  9.         }  
  10.     }  
  11. <pre name="code" class="java">void clearForRecycle() {  
  12.         flags = 0;  
  13.         what = 0;  
  14.         arg1 = 0;  
  15.         arg2 = 0;  
  16.         obj = null;  
  17.         replyTo = null;  
  18.         when = 0;  
  19.         target = null;  
  20.         callback = null;  
  21.         data = null;  
  22.     }  

在clearForRecycle这个函数中,是做一些回收的预处理的操作,该置为0的参数置为0,该置为null的参数置为null。在recycle的函数中,只要当前的缓存的队列的长度没有超过上限,将当前的消息添加到队列的尾部。

下面的方法是关于实现Parcelable所需要的方法:

[java]
  1. public static final Parcelable.Creator<CustomMessage> CREATOR  
  2.             = new Parcelable.Creator<CustomMessage>() {  
  3.         public Message createFromParcel(Parcel source) {  
  4.             Message msg = Message.obtain();  
  5.             msg.readFromParcel(source);  
  6.             return msg;  
  7.         }  
  8.           
  9.         public Message[] newArray(int size) {  
  10.             return new Message[size];  
  11.         }  
  12.     };  
  13.           
  14.     public int describeContents() {  
  15.         return 0;  
  16.     }  
  17.   
  18.     public void writeToParcel(Parcel dest, int flags) {  
  19.         if (callback != null) {  
  20.             throw new RuntimeException(  
  21.                 "Can't marshal callbacks across processes.");  
  22.         }  
  23.         dest.writeInt(what);  
  24.         dest.writeInt(arg1);  
  25.         dest.writeInt(arg2);  
  26.         if (obj != null) {  
  27.             try {  
  28.                 Parcelable p = (Parcelable)obj;  
  29.                 dest.writeInt(1);  
  30.                 dest.writeParcelable(p, flags);  
  31.             } catch (ClassCastException e) {  
  32.                 throw new RuntimeException(  
  33.                     "Can't marshal non-Parcelable objects across processes.");  
  34.             }  
  35.         } else {  
  36.             dest.writeInt(0);  
  37.         }  
  38.         dest.writeLong(when);  
  39.         dest.writeBundle(data);  
  40.         Messenger.writeMessengerOrNullToParcel(replyTo, dest);  
  41.     }  
  42.   
  43.     private void readFromParcel(Parcel source) {  
  44.         what = source.readInt();  
  45.         arg1 = source.readInt();  
  46.         arg2 = source.readInt();  
  47.         if (source.readInt() != 0) {  
  48.             obj = source.readParcelable(getClass().getClassLoader());  
  49.         }  
  50.         when = source.readLong();  
  51.         data = source.readBundle();  
  52.         replyTo = Messenger.readMessengerOrNullFromParcel(source);  
  53.     }  

Ok,Message的内核源码的剖析就讲解到这里

转载于:https://www.cnblogs.com/6060b/p/4192713.html

你可能感兴趣的文章
PMD使用提醒
查看>>
Codeforces 887D Ratings and Reality Shows
查看>>
论文《A Generative Entity-Mention Model for Linking Entities with Knowledge Base》
查看>>
Linux记录-salt分析
查看>>
Android Studio默认快捷键
查看>>
函数式编程与参数
查看>>
SSAS使用MDX生成脱机的多维数据集CUB文件
查看>>
HDU 2191 【多重背包】
查看>>
51nod 1433 0和5【数论/九余定理】
查看>>
【AHOI2013复仇】从一道题来看DFS及其优化的一般步骤和数组分层问题【转】
查看>>
less 分页显示文件内容
查看>>
如何对数据按某列进行分层处理
查看>>
[Qt] this application failed to start because it could not find or load the Qt platform plugin
查看>>
Git Submodule管理项目子模块
查看>>
学会和同事相处的30原则
查看>>
文件操作
查看>>
jquery基本选择器
查看>>
hdu 1010 dfs搜索
查看>>
搭建wamp环境,数据库基础知识
查看>>
android中DatePicker和TimePicker的使用
查看>>