Android性能优化那些事

在Android应用程序开发中关于性能的优化是一个永恒的话题,以下是在实际开发和学习中关于性能优化的一些见解。

1:内存管理

在Android系统上并没有为内存提供交换区,它是通过分页和内存映射的机制来管理内存,这就说明任何你修改的内存都会存在RAM中,因此唯一完整释放内存的方法是释放那些对象的引用,当这个对象没有被任何其他对象所引用的时候它就能够被GC回收。

(1):限制应用的内存

为了维持多任务的功能环境,Android为每一个app都设置了一个硬性的heap size限制。heap size的大小会因为不同设备的不同RAM大小而各有差异。如果你的app已经到了heap的限制大小并且再尝试分配内存的话,会引起OutOfMemoryError的错误。

你也许想要查询当前设备的heap size限制大小是多少,然后决定cache的大小。可以通过getMemoryClass()来查询。这个方法会返回一个整数,表明你的应用的heap size限制。

(2):切换应用

Android不会在用户切换应用时候做交换内存的操作。当用户刚开始启动了一个应用,系统会为它创建了一个进程,但是当用户离开这个应用,此进程并不会立即被销毁。系统会把这个进程放到cache中,如果用户后来再回到这个应用,此进程就能够被完整恢复,从而实现应用的快速切换。

如果你的应用中有一个被缓存的进程,这个进程会占用暂时不需要使用到的内存,会被保留在内存中,这会对系统的整体性能有影响。因此当系统开始进入低内存状态时,它会由系统根据特定的算法来kill进程。

(3):慎用Services

service用于在后台执行一些耗时操作,只用当它执行任务的时候才开启,否则其他时刻都应该不工作,service完成任务之后要主动停止,否则如果用户发现有常驻后台行为的应用并且可能卸载它甚至引起内存泄漏。

当你开启一个service,系统会倾向为了保留这个service而一直保留service所在的进程。这使得进程的运行代价很高,因为系统没有办法把service所占用的RAM空间腾出来让给其他组件。

推荐使用IntentService, 它会在工作线程处理完交代给它的intent任务之后自动停止。

(4):UI隐藏时释放内存

当应用 UI处于可见时,你应该释放你的应用UI上所占用的所有内存资源。在这个时候释放UI资源可以显著的增加系统缓存进程的能力,它会对用户体验有着很直接的影响。例如当用户从你的app的某个activity跳转到另外一个activity时前面activity的onStop()会被执行。因此你应该实现onStop回调,并且在此回调里面释放activity的资源,例如释放网络连接,注销监听广播接收者。

(5):避免盲目获取heap

可以通过在清单文件下的application标签下添加largeHeap=true的属性来声明一个更大的heap空间。如果你这样做,你可以通过getLargeMemoryClass())来获取到一个更大的heap size。

然而,能够获取更大heap的设计本意不是提供给整个应用,而是为了一小部分会消耗大量RAM的应用(例如一张图片的编辑)。不要盲目因为你需要使用大量的内存而去请求一个大的heap size。只有当你清楚的知道哪里会使用大量的内存并且为什么这些内存必须被保留时才去使用large heap。

需要说明的是通过设置large heap属性并不一定能够获取到更大的heap。在某些机器上,large heap的大小和通常的heap size是一样的。

(6):避免Bitmap浪费

加载一个bitmap时,仅仅需要保留适配当前屏幕设备分辨率的数据即可,如果原图高于你的设备分辨率,需要做缩小的动作。值得注意的是bitmap的尺寸会对内存呈现出2次方的增加。

(7):使用定制的数据容器

如SparseArray, SparseBooleanArray, 与 LongSparseArray。 通常的HashMap的实现方式更加消耗内存。SparseArray避免了key与value的自动装箱和拆箱。

(8):警惕内存开销

枚举类型的内存消耗通常是静态变量的2倍。你应该尽量避免在Android上使用枚举。

在Java中的每一个类(包括匿名内部类)都会使用大概500 bytes。

每一个类的实例开销大约是12-16 bytes。

向HashMap添加一个entry需要额一个额外占用的32 bytes的entry对象。

(9):谨慎使用第三方类库

如果一个类库与你的实际需求吻合度较小,你应该考虑自己去实现,而不是导入一个大而全的解决方案,因为它里面包含的各种资源也是对内存的消耗。

2:代码优化

高效的代码需要满足下面两个原则:

1.)不要做冗余的工作

2.)尽量避免过多的内存分配

(1):避免创建不必要的对象

避免创建更多的临时对象,更少的对象意味者更少的gc动作,即使gc支持并发操作但还是会对用户体验有比较直观的影响。

(2):选择使用Static

如果你不需要访问一个对象的值,请保证这个方法是static类型的,这样方法调用将快15%-20%。

(3):避免Getter和Setter方法

Getters和Setters方法在面向对象程序设计上是一个良好的习惯,但在Android上这不是一个好的写法,因为虚函数的调用比起直接访问变量要耗费更多。

(4):使用for-each 循环

for-each 循环可以被用在实现了 Iterable 接口的 collections 以及数组上,增强的for-each循环写法会和迭代器写法的效率一样,且更加清晰直观。

(5):避免使用float类型

Android系统中float类型的数据存取速度是int类型的一半,尽量优先采用int类型。

float 和 double 的速度是一样的,同样条件下使用 double 。

3:布局文件性能

Layout 是 Android 应用中直接影响用户体验的关键部分。如果实现的不好,你的 Layout 会导致程序非常占用内存并且 UI 运行缓慢。

(1):避免过多嵌套

 Layout转化为视图需要经过初始化、布局和绘制的过程,如果布局嵌套导致层级过深,上面的初始化,布局和绘制操作就更加耗时。

(2):使用include标签重用layouts

为了高效重用整个的 Layout,你可以使用include标签把其他 Layout 嵌入当前 Layout,比如可以把自定义的toolbar应用于每个需要的页面。

(3):ListView优化

ListView 滑动绘制Item时经常使用 findViewById(),这样会降低性能。即使是 Adapter 返回一个用于回收的 inflate 后的视图,你仍然需要查看这个元素并更新它。避免频繁调用 findViewById() 的y有效方法之一就是使用 ViewHolder。

4:多线程

(1):使用线程池

如果你只需要一个任务执行一次使用一个IntentService就可以。但是Android中的网络操作是相当频繁的,你需要提供一个管理线程的集合。 为了做这个管理线程的集合,使用一个ThreadPoolExecutor实例。

一个线程池能运行多个并行的任务实例,因此你要能保证你的代码是线程安全的,从而你需要给会被多个线程访问的变量加上同步代码块(synchronized block)。

(2):与UI线程通信

1.)Handler属于Android系统的线程管理框架的一部分,用于线程之间的通信。

2.)Rxjava能够很好的实现线程之间的相互切换。

5:ANR

ANR指应用程序无响应,发生原因通常是应用程序在UI线程执行耗时操作。比如:

Activity内对输入事件,5秒内都无响应。

BroadReceiver不能够在10秒内结束接收到任务。

(1):Android程序通常是执行在默认的UI线程中的。这意味着在UI线程中执行的任何长时间的操作都可能触发ANR,因此,任何执行在UI线程的方法都应该尽可能的快速。特别是,在activity的生命周期的方法onCreate()与onResume()方法中应该尽可能的做比较少的事情。类似网络或数据库操作等可能长时间执行的操作,都应该执行在工作线程中。

(2):BroadcastReceiver的超时时间是10秒,应用程序应该避免在BroadcastReceiver中执行费时的任务。如果需要的话可以启动一个IntentService来响应BroadcastReceiver的长时间任务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容