前言:

最近在做一个SDK的重构工作,app采集到信息,传递给持久化存储模块,数据存储到数据库中,上传模块定时拿取数据上传到服务器中。我负责的是数据持久化存储模块。数据持久存储这个功能简单的来说就是拿到数据后,写入到数据库中,需要的时候从数据库中提取出来就可以了。乍一看这么简单,但如果你想好好的设计一下的话,功能其实也不少。比如说:app数据传到我这个模块,模块拿到数据存储到数据库中,就是典型的生产消费者模型,感兴趣的朋友移步 LinkedBlockingQueue在生产消费者模式下的具体使用;app传递过来一个包含数据的bean类,使用完回收继续再用,类似Message.obtain()的一种缓冲池,这就是本篇文章要介绍的内容。

准备工作:

既然是参考Message.obtain()的方式构建一种缓冲池,那肯定得先阅读下Message的源码。首先Message.obtain()的构建方式:

public static Message obtain() {

synchronized (sPoolSync) {

if (sPool != null) {

Message m = sPool;

sPool = m.next;

m.next = null;

m.flags = 0; // clear in-use flag

sPoolSize--;

return m;

}

}

return new Message();

}

代码很简单,给sPoolSync加锁后,判断sPool是否为null,不为null则将sPool引用指向一个新的Message,并将新的Message的next的引用指向sPool,随即将next置空,标记重置,sPoolSize--,返回一个Message;如果sPool为null的话,直接new出一个Message。

那么这地方就涉及到几个变量:

/*package*/ Message next;

private static final Object sPoolSync = new Object();

private static Message sPool;

private static int sPoolSize = 0;

可以看到sPoolSync就是一个锁对象,只读不写,final修饰;而

Message m = sPool;

sPool = m.next;

就是一个单链表的结构,将sPool指向当前Message,Message的next指向下一个Message。

那么回收的方法:

public void recycle() {

if (isInUse()) {

if (gCheckRecycle) {

throw new IllegalStateException("This message cannot be recycled because it "

+ "is still in use.");

}

return;

}

recycleUnchecked();

}

先是判断了isInUse()是否在使用这个Message,然后调用recycleUnchecked()回收:

void recycleUnchecked() {

// Mark the message as in use while it remains in the recycled object pool.

// Clear out all other details.

flags = FLAG_IN_USE;

what = 0;

arg1 = 0;

arg2 = 0;

obj = null;

replyTo = null;

sendingUid = -1;

when = 0;

target = null;

callback = null;

data = null;

synchronized (sPoolSync) {

if (sPoolSize < MAX_POOL_SIZE) {

next = sPool;

sPool = this;

sPoolSize++;

}

}

}

前半段是重置各种数值,后半段是核心代码:

synchronized (sPoolSync) {

if (sPoolSize < MAX_POOL_SIZE) {

next = sPool;

sPool = this;

sPoolSize++;

}

}

判断当前缓存池sPoolSize是否小于设定的最大缓冲池大小,如果小于这个值,则将sPool指向下一个Message,当前Message指向sPool,sPoolSize++,相当于回收了这个使用过的Message。

实践:

看懂了Message的源码,发现实现一个缓冲池也挺简单,只需要在你需要实现缓存池的类中,实现上述的复用和回收两个方法,标记一个数值,判断是否在使用,然后就可以愉快的使用缓存池了。

我们的事件类EventMessage,同Message:

private static final Object sPoolSync = new Object();//锁对象

private static EventMessage sPool;

private static int sPoolSize = 0;

private static final int MAX_POOL_SIZE = 50;//缓存池大小

private EventMessage next;

由于我们的功能比较简单,只需要一个boolean值判断有没有在使用就行了,不需要Message的flag还要判断同步异步,所以:

private boolean use;

private boolean isInUse() {

return use;

}

obtain方法:

public static EventMessage obtain() {

synchronized (sPoolSync) {

if (sPool != null) {

LogHelper.d("缓存池取出");

EventMessage m = sPool;

sPool = m.next;

m.next = null;

m.use = false;

sPoolSize--;

LogHelper.d("缓存池取出,缓存池= " + sPoolSize);

return m;

}

}

LogHelper.d("创建新的对象,缓冲池 = " + sPoolSize);

return new EventMessage();

}

recycle方法:

/**

* 回收

*/

public void recycle() {

if (isInUse()) {

return;

}

recycleUnchecked();

}

private void recycleUnchecked() {

use = false;

resetFiled();//重置所有属性

synchronized (sPoolSync) {

if (sPoolSize < MAX_POOL_SIZE) {

next = sPool;

sPool = this;

sPoolSize++;

LogHelper.d("回收,缓存池=" + sPoolSize);

}

}

}

然后再你需要使用这个EventMessage的时候调用下

public void setUse(boolean use) {

this.use = use;

}

在使用完这个EventMessage调用下recycle方法就可以了。

上测试结果:

1.PNG

2.PNG

多次尝试一切正常

完全ojbk

android obtain,Android 模拟Message.obtain(),构建自己的缓存池相关推荐

  1. android 模拟手指点击,『Android Tip』-- 模拟手势操作

    平时 Android 开发中总会遇到奇葩的功能或者需求,这里做个记录和积累,以便后面开发过程中遇到类似的问题,可以快速的解决.Android tips 前言 这个版本终于快结束了,历时一个月的时间,这 ...

  2. Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)

    不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Message.obtain() 消息的回收利用 MessageQueue MessageQueue ...

  3. android message的作用,Android消息机制之Message解析(面试)

    在android的消息机制中,Message其充当着信息载体的一个角色,通俗的来说,我们看作消息机制就是个工厂的流水线,message就是流水线上的产品,messageQueue就是流水线的传送带.之 ...

  4. Android系统中模拟GPS位置,Android系统中模拟GPS位置

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? Android系统中提供了模拟GPS坐标的功能,可以很方便的帮助我们测试不同地理位置下应用中各个功能效果. 模拟器中模拟 ...

  5. Android的消息机制: Message/MessageQueue/Handler/Looper

    概览 * Message:消息.消息里面可包含简单数据.Object和Bundle,还可以包含一个Runnable(实际上可看做回调). * MessageQueue:消息队列,供Looper线程消费 ...

  6. 关于在用异步消息处理机制使用Message.Obtain()方法(而非New Message)获得一个Message对象的好处

    类概述 定义一个包含任意类型的描述数据对象,此对象可以发送给Handler.对象包含两个额外的int字段和一个额外的对象字段,这样可以使得在很多情况下不用做分配工作. 尽管Message的构造器是公开 ...

  7. Android上的模拟点击

    模拟点击在 Android 上有2种情况: 1,只模拟点击自己的页面: 2,只要自己进程活着,不管是哪个应用在前台,都可以模拟点击: 第一种情况比较简单: long downTime = System ...

  8. 【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 拷贝 lib7zr.so 动态库头文件到 Android 工程中 | 配置 CMakeLists.txt 构建脚本 )

    文章目录 一.拷贝 p7zip 源码中的头文件到 Android Studio 项目中 二.配置 CMakeLists.txt 构建脚本 1.导入动态库 2.导入头文件 三.完整 CMakeLists ...

  9. android x86还是arm,Android x86是否模拟ARM?(Does Android x86 emulate ARM?)

    Android x86是否模拟ARM?(Does Android x86 emulate ARM?) 试图找出应用程序在为ARM编译时如何在VMWare上的Android x86上工作. GUI是否在 ...

  10. android学习:模拟微博看看界面

    这几天学会了ListView组件,这个组件真的很有用.希望在今后的开发中能大量用到. 通过ListView的学习,模拟了新浪微博的随便看看页面. 要实现的效果: 代码如下: [html] view p ...

最新文章

  1. React组件通信技巧
  2. ES 查询数据的工作原理是什么?
  3. Java黑皮书课后题第6章:**6.18(检测密码)一些网站对于密码具有一些规则。编写一个方法检测字符串是否是一个有效密码。编写一个程序,提示用户输入一个密码,如果符合规则,则显示…否则显示…
  4. php+node+redis,redis,nodejs,php,pub/sub 实战: 微信语音识别
  5. java的正则表达式 CPU_小心踩雷!一个小小的正则表达式竟把CPU拖垮......
  6. javafx弹出式窗口_JavaFX 8的弹出式编辑器
  7. 21秋期末考试建筑力学与结构10126k2
  8. 医动力Android基于CC组件化框架的探索与实践
  9. 由二分查找算法学习算法的时间复杂度
  10. python自动输入账号密码_Python如何基于selenium实现自动登录博客园
  11. 打球崴脚,运动崴脚怎么办?这里有一份最强处置指南
  12. 慕课网上的星级评分--学习视频后模仿实现
  13. 浅谈信息学奥赛NOIP
  14. detached entity passed to persist:xxx;
  15. oracle 如何判断当前日期是星期几
  16. 京东评价项目示例——在线分析及可视化
  17. php反序列化漏洞中当不存在__invoke时的一种利用思路
  18. 二维码制作方法有哪些?教你简单的二维码制作方法
  19. window.frames用法
  20. ffmpeg mkv 转 MP4

热门文章

  1. 离线安装keras的主要步骤
  2. 基于STM32+华为云IOT设计智能称重系统
  3. PowerShell复制粘贴快捷键
  4. 计算机桌面图标右上角出现双箭头符号,建议这样去掉桌面快捷图标的小箭头-word箭头符号...
  5. 搭建简易的asp服务器 用于手机安装测试程序
  6. jeeplus-一款款可一键生成前后端代码的开发平台
  7. 各种把妹法——太强大了!
  8. 三星手机tf卡数据恢复怎么做
  9. 东财《领导科学X》综合作业
  10. 使用Sbo用户自定义业务对象