如何通过 ArrayMap 和 SparseArray 优化 Android App

本文讲的是如何通过 ArrayMap 和 SparseArray 优化 Android App,


这篇文章会讲述为何要使用 ArrayMap 和 SparseArray 来优化 Android 应用,以及什么情形下适用。

当你需要存储键 -> 值这样的数据类型时,你脑海里想到的第一个数据类型应该是 HashMap。然后你开始肆无忌惮地到处使用它,而从不考虑它所带来的副作用。

当你使用 HashMap 时,你的 Android 集成开发环境 (Android Studio) 会给出警告,提示你使用 ArrayMap 来代替 HashMap,但通常被你忽视了。

Android 给你提供了 ArrayMap,你应该优先考虑使用它而不是 HashMap。

现在,让我们来理解 ArrayMap 的内部实现,以便探求在哪种场景下使用它,以及为什么这样做。

HashMap vs ArrayMap

HashMap 的位置在 java.util.HashMap 包中。

ArrayMap 的位置在 android.util.ArrayMap 和 android.support.v4.util.ArrayMap 包中。

它存在于 support.v4 包中,以便兼容较低的 Android 版本。

这里 是直接出自 Android 开发者频道的 youtube 视频,强烈建议你看一下。

ArrayMap 是一种通用的键->值映射数据结构,它在设计上比传统的 HashMap 更多考虑内存优化。 它使用两个数组来存储数据——一个整型数组存储键的哈希值,另一个对象数组存储键/值对。这样既能避免为每个存入 map 中的键创建额外的对象,还能更积极地控制这些数组的长度的增加(因为增加长度只需拷贝数组中的键,而不是重新构建一个哈希表)。

需要注意的是,ArrayMap 并不适用于可能含有大量条目的数据类型。它通常比 HashMap 要慢,因为在查找时需要进行二分查找,增加或删除时,需要在数组中插入或删除键。对于一个最多含有几百条目的容器来说,它们的性能差异并不巨大,相差不到 50%。

HashMap

HashMap 基本上就是一个 HashMap.Entry 的数组(Entry 是 HashMap 的一个内部类)。更准确来说,Entry 类中包含以下字段:

  • 一个非基本数据类型的 key
  • 一个非基本数据类型的 value
  • 保存对象的哈希值
  • 指向下一个 Entry 的指针

当有键值对插入时,HashMap 会发生什么 ?

  • 首先,键的哈希值被计算出来,然后这个值会赋给 Entry 类中对应的 hashCode 变量。
  • 然后,使用这个哈希值找到它将要被存入的数组中“桶”的索引。
  • 如果该位置的“桶”中已经有一个元素,那么新的元素会被插入到“桶”的头部,next 指向上一个元素——本质上使“桶”形成链表。

现在,当你用 key 去查询值时,时间复杂度是 O(1)。

虽然时间上 HashMap 更快,但同时它也花费了更多的内存空间。

缺点:

  • 自动装箱的存在意味着每一次插入都会有额外的对象创建。这跟垃圾回收机制一样也会影响到内存的利用。
  • HashMap.Entry 对象本身是一层额外需要被创建以及被垃圾回收的对象。
  • “桶” 在 HashMap 每次被压缩或扩容的时候都会被重新安排。这个操作会随着对象数量的增长而变得开销极大。

在Android中,当涉及到快速响应的应用时,内存至关重要,因为持续地分发和释放内存会出发垃圾回收机制,这会拖慢应用运行。

垃圾回收机制会影响应用性能表现

垃圾回收时间段内,应用程序是不会运行的,最终应用使用上就显得卡顿。

ArrayMap

ArrayMap 使用2个数组。它的对象实例内部有用来存储对象的 Object[] mArray 和 存储哈希值的 int[] mHashes。当插入一个键值对时:

  • 键/值被自动装箱。
  • 键对象被插入到 mArray[] 数组中的下一个空闲位置。
  • 值对象也会被插入到 mArray[] 数组中与键对象相邻的位置。
  • 键的哈希值会被计算出来并被插入到 mHashes[] 数组中的下一个空闲位置。

对于查找一个 key :

  • 键的哈希值先被计算出来
  • 在 mHashes[] 数组中二分查找此哈希值。这表明查找的时间复杂度增加到了 O(logN)。
  • 一旦得到了哈希值所对应的索引 index,键值对中的键就存储在 mArray[2index] ,值存储在 mArray[2index+1]。
  • 这里的时间复杂度从 O(1) 上升到 O(logN),但是内存效率提升了。当我们在 100 左右的数据量范围内尝试时,没有耗时的问题,察觉不到时间上的差异,但我们应用的内存效率获得了提高。

推荐的数据结构:

  • ArrayMap<K,V> 替代 HashMap<K,V>
  • ArraySet<K,V> 替代 HashSet<K,V>
  • SparseArray<V> 替代 HashMap<Integer,V>
  • SparseBooleanArray 替代 HashMap<Integer,Boolean>
  • SparseIntArray 替代 HashMap<Integer,Integer>
  • SparseLongArray 替代 HashMap<Integer,Long>
  • LongSparseArray<V> 替代 HashMap<Long,V>





原文发布时间为:2016年10月30日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2024-09-03 17:37:38

如何通过 ArrayMap 和 SparseArray 优化 Android App的相关文章

优化Android App性能?十大技巧必知!

http://blog.csdn.net/qijianke2014/article/details/40041331 无论锤子还是茄子手机的不断冒出,Android系统的手机市场占有率目前来说还是最大的,因此基于Android开发的App数量也是很庞大的.那么,如何能开发出更高性能的Android App?相信是软件开发公司以及广大程序员们头疼的一大难题.今天,就给大家提供几个提高Android App性能的技巧. 高效地利用线程 1.在后台取消一些线程中的动作 我们知道App运行过程中所有的操

android优化-android APP 内存与速度的优化问题。。。

问题描述 android APP 内存与速度的优化问题... android APP 内存与速度的优化问题... 我最近写了一个APP 一开就用了很多资源...请问怎么来优化内存,速度... 大家可以谈谈从代码,或者风格,框架方面谈谈... 解决方案 性能优化 Android应用程序运行的移动设备受限于其运算能力,存储空间,及电池续航.由此,它必须是高效的.电池续航可能是一个促使你优化程序的原因,即使他看起来已经运行的足够快了.由于续航对用户的重要性,当电量耗损陡增时,意味这用户迟早会发现是由于

内存优化-Android app被系统回收之后,闪白屏

问题描述 Android app被系统回收之后,闪白屏 当前开发的app占用内存大,在按home键挂在后台一段时间,会被系统回收! 然后重新点击图标打开的时候,屏幕闪白屏,过了几秒才会成功打开到主页面 问:我怎么可以把白屏用欢迎页代替,不然用户体验超级不好!谢谢···· 解决方案 application里面有一个低内存的回调方法,不妨试一下 解决方案二: onResume的时候判断下界面状态

Android APP启动方式、启动流程及启动优化分析_Android

本文章向大家介绍Android app应用启动的一些相关知识,包括app启动方式.app启动流程和app启动优化等知识!  app应用启动方式 1.冷启动  当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动.冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量.布局.绘制),最后显示在界面上. 2.热启动 当启动应用时,后台已有该应用的进程(例:

总结Android App内存优化之图片优化_Android

前言 在Android设备内存动不动就上G的情况下,的确没有必要去太在意APP对Android系统内存的消耗,但在实际工作中我做的是教育类的小学APP,APP中的按钮.背景.动画变换基本上全是图片,在2K屏上(分辨率2048*1536)一张背景图片就会占用内存12M,来回切换几次内存占用就会增涨到上百兆,为了在不影响APP的视觉效果的前提下,有必要通过各种手段来降低APP对内存的消耗. 通过DDMS的APP内存占用查看工具分析发现,APP中占用内存最多的是图片,每个Activity中图片占用内存

Android APP启动方式、启动流程及启动优化分析

本文章向大家介绍Android app应用启动的一些相关知识,包括app启动方式.app启动流程和app启动优化等知识! app应用启动方式 1.冷启动 当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动.冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量.布局.绘制),最后显示在界面上. 2.热启动 当启动应用时,后台已有该应用的进程(例:按b

Pury — 一个新的 Android App 性能分析工具

本文讲的是Pury - 一个新的 Android App 性能分析工具, 手机应用存在的目的,就是在帮助用户做他们想做的事情的同时,提供最好的用户体验 -- 而用户体验的重中之重是应用的性能.但有时候开发者们却以性能为借口,既没有达到既定目标,又写着低质量并难以维护的代码.在这里我想引用 Michael A. Jackson 的一句话: "程序优化守则第一条:别去做它.程序优化守则第二条(仅限于专业人员):别去做它,现在还不是时候." 在开始任何优化之前,我们要先认清问题的症结所在.

携程Android App的插件化和动态加载框架

携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实现细节,回顾携程Android App的架构演化过程,期望我们的经验能帮助到更多的Android工程师. 需求驱动 2014年,随着业务发展需要和携程无线部门的拆分,各业务产品模块归属到各业务BU,原有携程无线App开发团队被分为基础框架.酒店.机票.火车票等多个开发团队,从此携程App的开发和发布

我的Android进阶之旅------&amp;gt;Android APP终极瘦身指南

首先声明,下面文字转载于: APK瘦身实践 http://www.jayfeng.com/2015/12/29/APK%E7%98%A6%E8%BA%AB%E5%AE%9E%E8%B7%B5/ APP终极瘦身指南 http://www.jayfeng.com/2016/03/01/Android-APP%E7%BB%88%E6%9E%81%E7%98%A6%E8%BA%AB%E6%8C%87%E5%8D%97/