2019独角兽企业重金招聘Python工程师标准>>>

操作过Android手机的朋友应该对在待机界面拖动图标的交互效果都有比较深刻的印象,比如说,当把图标拖动起来,图标会悬浮并随着拖动变换位置,当拖动释放后,图标会自动的寻找附近合适的空白网格位置。Android在实现这个效果的过程中采用了很多编程技巧,本文着重论述的VacantCell缓存就很具有代表性。

VacantCell缓存主要是对同一种类型对象的缓存机制,这种机制的目的是复用已经分配过但已过期的对象,从而避免频繁的new新的对象。我们知道对象分配是一件比较耗费系统资源的事情,在需要频繁、大量的分配对象的时候Android平台很可能出现堆内存不足进而导致系统变慢、应用报错重启等严重问题。用户在待机界面拖动图标是很频繁的事情,而Android的屏幕中空白网格的寻址算法就采用了这种VacantCell缓存来避免频繁new大量新的对象。

VacantCell类的实现其实很简单,就不到50行实现代码:

[java]  view plain copy
  1. static final class VacantCell {
  2. int cellX;
  3. int cellY;
  4. int spanX;
  5. int spanY;
  6. // We can create up to 523 vacant cells on a 4x4 grid, 100 seems
  7. // like a reasonable compromise given the size of a VacantCell and
  8. // the fact that the user is not likely to touch an empty 4x4 grid
  9. // very often
  10. private static final int POOL_LIMIT = 100;
  11. private static final Object sLock = new Object();
  12. private static int sAcquiredCount = 0;
  13. private static VacantCell sRoot;
  14. private VacantCell next;
  15. static VacantCell acquire() {
  16. synchronized (sLock) {
  17. if (sRoot == null) {
  18. return new VacantCell();
  19. }
  20. VacantCell info = sRoot;
  21. sRoot = info.next;
  22. sAcquiredCount--;
  23. return info;
  24. }
  25. }
  26. void release() {
  27. synchronized (sLock) {
  28. if (sAcquiredCount < POOL_LIMIT) {
  29. sAcquiredCount++;
  30. next = sRoot;
  31. sRoot = this;
  32. }
  33. }
  34. }
  35. @Override
  36. public String toString() {
  37. return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
  38. ", spanY=" + spanY + "]";
  39. }
  40. }

可以看到,VacantCell实际上是一个Java静态内部类,其外部类CellLayout.java的代码路径是\packages\apps\Launcher2\src\com\android\launcher2\CellLayout.java(具体如何下载Android gingerbread Launcher单个模块的下载方法见博文Android源码下载——用git clone实现单个目录下载)。

下面我们具体分析下VacantCell的缓冲机制是如何实现的。

cellX、cellY、spanX、spanY几个成员是空白网格的纵横索引号和占据相应单元网格数,我们这里可以不用关心。

POOL_LIMIT定义了可以缓存的VacantCell的最大值,正如注释所说,最多可以分配多达523个VacantCell对象,但是对于4X4的屏幕网格定义来说,100个的缓冲数应该是足够的了。也就是说,这个100的数值是一个经验值,我们可以根据实际情况作灵活修改。

sLock是一个Java Object对象,主要是拿来作同步控制的,我们可以不用关心。

sAcquiredCount是一个非常重要的变量,其实际上就是一个计数器,实时的统计当前缓存了多少个VacantCell对象值。根据这个计数器和POOL_LIMIT可以控制缓存对象不超过POOL_LIMIT的上限。

sRoot和next是缓存VacantCell对象链式存储的两个关键引用,分别表示VacantCell对象链表的表头和特定VacantCell对象链接的下一对象的引用。

好了,下面介绍VacantCell缓存的两个关键静态方法acquire()和非静态方法release()。

当需要VacantCell新对象的时候,Launcher会调用静态内部类的VacantCell的静态方法acquire()以获取新的VacantCell对象。请注意,这里获取新对象不是直接new一个VacantCell对象,而是acquire的。我们看acquire方法的内部,当sRoot为null的时候,是直接new VacantCell并直接return的,因为这个时候实际上还没有缓存可用;当sRoot不为null,这意味着已经有缓存的VacantCell对象了,那么直接从链表中取出sRoot指向的对象,并将sRoot所在对象指向的next作为新的表头sRoot,同时把sAcquiredCount计数减1。这实际上是一种典型的从链表中删除表头的操作,相信熟悉数据结构的朋友对此都不会陌生。

如果说acquire()方法提供的是如何利用VacantCell链式缓存,那么release()方法解决的就是如何构建VacantCell链式缓存的问题。我们看到,只有sAcquiredCount < POOL_LIMIT的前提下才会将VacantCell对象加入链式缓存。将当前VacantCell对象加入链式存储也很简单,将当前VacantCell对象的next指向原来的表头,将静态sRoot应用指向当前对象,同时sAcquiredCount加1。也就是说,这个操作其实就是把当前VacantCell对象插入VacantCell链表的表头。

那么如何使用这个VacantCell对象缓存呢?第一,当需要新的VacantCell对象的时候,通过调用VacantCell的静态方法acquire()来获取对象,而不是直接new VacantCell对象;第二,当一个VacantCell对象已经过期,不再需要的时候,调用该对象的release()方法将这个不再需要的对象加入缓存。

需要指出的是,如果直接new VacantCell对象也不会有直接的问题,只不过这意味着没有采用VacantCell缓存机制;如果一个对象不需要时不显示调用release()方法也不会有直接的问题,这意味着这个对象不会加入进VacantCell缓存链表,当没有链表各节点对象的引用关联,这个对象最终将被Android的Dalvik虚拟机当做垃圾自动回收。

本文详细分析了Android Launcher模块VacantCell缓存的实现原理,当我们需要频繁构造、释放大量的相同类型的Java对象的时候,我们考虑采用类似的缓存机制,这在某些场合下能有效的解决频繁分配对象导致的内存不足的问题。

转载于:https://my.oschina.net/u/724887/blog/91274

android原理揭秘系列之VacantCell缓存相关推荐

  1. Android原理揭秘系列之动态墙纸

    Livewallpaper,即动态墙纸,是Android的一大3D特色功能,用户可以在桌面选择加载动态墙纸,让自己的手机桌面背景旋动起来. 相对于静态桌面壁纸,动态墙纸可以展示各种动态变化的背景,而与 ...

  2. android 图片缓存工具类,Android工具类系列-Glide图片缓存与圆角

    Glide的图片缓存和清除图片缓存 public class GlideCacheUtil { private static GlideCacheUtil inst; public static Gl ...

  3. Android后台杀死系列之三:LowMemoryKiller原理(4.3-6.0)

    本篇是Android后台杀死系列的第三篇,前面两篇已经对后台杀死注意事项,杀死恢复机制做了分析,本篇主要讲解的是Android后台杀死原理.相对于后台杀死恢复,LowMemoryKiller原理相对简 ...

  4. Android学习系列(27)--App缓存管理

    随笔- 53 文章- 10 评论- 1064 Android学习系列(27)--App缓存管理 无论大型或小型应用,灵活的缓存可以说不仅大大减轻了服务器的压力,而且因为更快速的用户体验而方便了用户. ...

  5. Android自定义控件开发系列(零)——基础原理篇

    在后边的文章中发现在说Android自定义时,有时候要重复解释很多东西,所以想想返回来增加一篇"基础原理篇",直接进入正题吧-- 首先的问题是:在Android项目开发中,什么时候 ...

  6. vacantcell缓存分析

    http://blog.csdn.net/droidpioneer/article/details/6758057 操作过Android手机的朋友应该对在待机界面拖动图标的交互效果都有比较深刻的印象, ...

  7. 新书《Android安全技术揭秘与防范》终于出版了

    愿每一个北漂的孩子都能找到自己为之奋斗的方向,不负那些在远方默默支持我们的父母和亲人. 历时将近1的新书<Android安全技术揭秘与防范>终于出版了,第一次写书万分激动,这里向大家推广一 ...

  8. Connor学Android - Bitmap的加载和缓存策略

    Learn && Live 虚度年华浮萍于世,勤学善思至死不渝 前言 Hey,欢迎阅读Connor学Android系列,这个系列记录了我的Android原理知识学习.复盘过程,欢迎各位 ...

  9. Android Performance Patterns 系列视频学习记录(持续更新中)

    系列文章旨在记录YouTube上谷歌发布的Android Performance Patterns系列视频,一共79个视频,每个视频也就几分钟.当然对于大部分安卓开发者来说,这些都是基础,可能你会说, ...

最新文章

  1. 斯坦福CS330 2019秋季课程视频全新上线,专注多任务与元学习
  2. Spring之 Bean的自动装配
  3. 逆水寒斩鸿蒙称号,逆水寒胆大包天称号怎么获得 逆水寒胆大包天称号获得方法一览...
  4. A股开盘:深证区块链50指数涨0.02%,仁东控股跌停
  5. CodeBlocks常用操作快捷键
  6. 超详细中文车牌识别开源库EasyPR入门实战(win10_VS2019_opencv34)
  7. openwrt打印服务器硬件需求,openwrt打印服务器
  8. 计算机科学与技术双一流名单,重磅 | 解读“双一流”名单(附完整名单)
  9. (附源码)Springboot小型仪器公司生产管理系统 毕业设计 031853
  10. Excel数据透视表如何创建?
  11. Python回归分析五部曲(三)—一元非线性回归
  12. 《二十世纪西方思想文化潮流》笔记--导论5--理性的后果1
  13. Python 助你填写高考志愿
  14. 不行不行,不能再讨厌英语了,要爱上英语。。。I Love You。。。
  15. idea验证失败_阿里云滑块验证失败解决方案
  16. FPS类游戏的逆向分析通用方法与C++逆向功能开发详解
  17. 耳部穴位取穴 耳朵对应身体各部位反射图
  18. 【面试分享】GitHub上Star大佬是如何一举拿下7家一线互联网大厂的Offer
  19. 常见鸟的种类及特点_鸟的分类
  20. java 免登录_最简单、稳定的免密登录

热门文章

  1. 故障排错-解决迅雷播放器在Windows 10中长时间停止响应
  2. 根据开发提供的svn更新版本号从开发分支合并代码到测试分支工作目录的部分脚本...
  3. C语言 多维数组和指针
  4. DPDK — TestPMD
  5. 数据结构 — 双向链表
  6. LVS 四层 TCP/UDP 负载均衡器
  7. linux中ping命令的用法
  8. MDI接口原理图设计
  9. 身为程序员,你接过最奇葩的需求是什么?丨Q言Q语
  10. 设计模式——外观模式