Android性能优化

Android性能优化,也是面试中几乎必问的知识点。本文也将告诉你如何回答这样的问题。

实际项目中的Android性能优化主要有如下几个方面:

  • 编写高效代码—开发中总结出的一些小的性能Tips

  • Layout布局优化

  • 内存优化

编写高效代码

本节告诉你如何编写高效代码,并总结了一些小的性能优化点。

编写高效代码的两个原则

  • 不要写不需要的代码

  • 不要分配不必要的内存

以上两个原则,似乎感觉是废话,但确实是编程的最高境界,也是我们编写代码的过程中时刻需要思考和注意的两个方面。

那么如何做到如上两点呢?下面列出了一些实际开发中的小的例子。

1.避免产生不必要的对象

例如:

  • int的数组比Integer对象数组要好得多。两个平行的int数组要比一个(int,int)型的对象数组高效。这对于其他任何基本数据类型的组合都通用

  • 两个平行数组Foo[],Bar[]会优于一个(Foo,Bar)对象的数组

  • 通常来讲,尽量避免创建短时零时对象.少的对象创建意味着低频的垃圾回收

对象的分配和回收都是需要代价的;分配的内存越多,就会引起强制的内存回收;给用户体验增加小的停顿间隙,从而影响用户体验。

用户能感觉到卡顿的时间延迟是100ms ~ 200ms。

2.用静态代替虚拟

  • 如果方法不需要访问某对像的字段,将该方法设置为静态,调用速度会提升15%~20%

  • 对于常量使用 final static

final static int intVal = 42;         
final static String strVal = "Hello world";

注:这种优化仅仅是针对基本数据类型和String类型常量的,而非任意的引用类型。但尽可能的将常量声明为static final是一种好的做法。

为什么尽量将将常量声明为static final是一种好的做法呢?这是因为:

  1. 当上面的代码块没有final修饰符时,编译器会生成一个类初始化方法,当该类初次被使用时执行,这个方法将42存入intVal中,并得到类文件字符串常量strVal的一个引用。当这些值在后面被引用时,他们通过字段查找进行访问。

  2. 声明为final字段后, 类不再需要方法,因为常量通过静态字段初始化器载进入dex文件中。引用intVal的代码,将直接调用整型值42;而访问strVal,也会采用相对开销较小的“字符串常量”指令替代字段查找。

本节讨论的是一些微小的性能提升,可能不会给你的程序性能改善产生显著的效果。决定程序整体性能的仍然取决于程序的业务逻辑设计、代码的数据结构和算法。但你需要将这些优化技巧应用到平时的编码过程中,积少成多,也会对性能有很大的影响

3.避免内部的getter和setter

4.使用增强for循环

对于ArrayList和数组,手写的计数循环迭代要比增强for循环快3倍

结论:优先采用改进for循环,但在性能要求苛刻的ArrayList迭代中,考虑采用手写计数循环。 (参见 Effective Java item 46.)

5.避免使用浮点数

通常的经验是,在Android设备中,浮点数会比整型慢两倍

6.在没有JIT的设备上,调用方法所传递的对象采用具体的类型而非接口类型会更高效

void methodA(List<String> list);void methodA(ArrayList<String> list);

如上,后一种比前一种更高效。

7.数据库操作方法的优化

  • 尽量利用原生的SQL语句

    原生的SQL省去了拼接sql语句的步骤,要比SqliteDatabase提供的insert、query、 update、delete等函数效率高。当数据库越大,差别也越大

  • 当操作条数较多时,利用事务进行批处理

    这样SQLite将把全部要执行的SQL语句先缓存在内存当中,然后等到COMMIT的时候一次性的写入数据库,这样数据库文件只被打开关闭了一次,效率自然大大的提高

 db.beginTransaction();        for(Collection c:colls){
    insert(db, c);
 } 
db.setTransactionSuccessful();

8.Http请求方式的选择

Android 内置了两种HTTP方式:HttpURLConnection 和 Apache HttpClient。这两种都支持HTTPS、流式上传和下载、可配置超时、IPv6和连接池。在Gingerbread或者更高版本时,推荐使用HttpURLConnection。

这是因为: HttpURLConnection API 更简单,包更小。同时对传输数据的压缩和响应的缓存处理减少了网络带宽、提高了速度,也节省了电量。

优化布局

Layouts是Android应用里直接影响用户体验的一个关键部分。如果Layout设计的不好,可能导致你的应用大量的内存占用从而导致UI响应很慢。Android SDK提供了工具帮助你分析你的Layouts的性能问题。结合工具同时遵循本节讨论的做法,能实现滑动流畅、占用内存最小的用户界面。

使用Hierarchy Viewer

Hierarchy Viewer工具位于 < SDK >\tools\目录下 ,该工具能分析出你的布局不合理和可以优化的地方。具体用法参见之前文章的介绍例子。

大多数情况下,布局渲染时间差别较大的原因是在LinaerLayout里使用了layout_weight。这将会增加测量(Measure)的时间。你应该仔细的考虑是否有必要使用layout weight。

使用Lint

使用Lint — 查看你的view 层级哪些地方可以优化

  1. 使用compound drawables - 一个包含了ImageView与TextView的LinearLayout可以被当作一个compound drawable来处理

  2. 使用merge根框架 - 如果FramLayout仅仅是一个纯粹的(没有设置背景,间距等)布局根元素,我们可以使用merge标签来当作根标签

  3. 无用的分支 - 如果一个layout并没有任何子组件,那么可以被移除,这样可以提高效率

  4. 无用的父控件 - 如果一个layout只有子控件,没有兄弟控件,并且不是一个ScrollView或者根节点,而且没有设置背景,那么我们可以移除这个父控件,直接把子控件提升为父控件

  5. 深层次的layout - 尽量减少内嵌的层级,考虑使用更多平级的组件 RelativeLayout or GridLayout来提升布局性能,默认最大的深度是10

其他一些布局有点

  1. Re-using Layouts with <include/>

  2. Use the <merge>

  3. Loading Views on Demand

 <ViewStub             android:id="@+id/stub_import"
     android:inflatedId="@+id/panel_import"                     android:layout="@layout/progress_overlay ….
  />

优化App内存

为了垃圾回收器能回收你系统的内存,你应该避免引起内存泄露(通常由全局成员hold了对象引用),而且要在合适的时间点(如生命周期回调时,这将在后面章节进一步讨论)释放被引用的对象。

慎用Service

  1. Service执行完后台任务后要停止,注意:不要service任务已完成,而不去停止service

  2. 使用IntentService

    IntentService不同于普通的Service之处是:

    • 提交的task会系统会post到子线程运行

    • 当后台运行的task完成时,系统会stop掉IntentService

onHandleIntent(Intent intent)

当一个service不需要而还在后台运行时,这是最消耗内存的内存管理错误。因此要慎用服务,当服务完成后台任务时要记得关闭。如果不这样做,由于RAM的限制,你的app运行将变得非常卡,用户也将发现app错误的行为,最后卸载你的应用

Release memory when your user interface becomes hidden

例如,在该onStop()里做释放资源(例如网络连接、注销广播等)的工作

使用优化后的集合容器

例如:SparseArray、SparseBooleanArray、LongSpareArray …..

尽量避免使用枚举

相比于静态常量,枚举会有超过其两倍以上的内存开销,在android中需严格避免使用枚举

避免使用依赖注入框架

使用ProGuard消除没有使用的代码

使用zipalign优化和对齐你的apk

  1. 优化避免使用更多的内存、资源不会再从apk中映射入内存。

注:google play store不接受没有进行zipalign的apk

使用MAT分析和优化内存

  1. I/O使用后需要关闭,数据库和Cursor等使用后要关闭

  2. 使用finalize()+MAT 分析内存泄露

Android优化主要就是内存、布局和性能的优化,本文概况和总结了Android中优化的一些知识点。其实,里面的很多的知识点都可以展开进行讲解。如果大家对里面某个方面感兴趣,可以给我们留言。后续的文章我们会进行专门的讨论。


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