写出高效的代码需要遵循两条原则:
不执行不必要的操作;
不分配不必要的内存;
两条原则分别针对CPU和内存,完成必要操作的前提下尽可能的节省CPU和内存资源,自然执行效率要高。单纯这样说听起来很虚,毕竟没有一个统一的标准判断什么是必要和不必要的,需要结合具体情况具体分析了。
1. 避免创建不必要的对象
创建太多的对象会造成性能低下,这谁都知道,可是为什么呢?首先分配内存本身需要时间,其次虚拟机运行时堆内存使用量是有上限的,当使用量到达一定程度时会触发垃圾回收,垃圾回收会使得线程甚至是整个进程暂停运行。可想而知,如果有对象频繁的创建和销毁,或者内存使用率很高,就会造成应用程序严重卡顿。
2.合理使用static成员
主要有三点需要掌握: 如果一个方法不需要操作运行时的动态变量和方法,那么可以将方法设置为static的。 常量字段要声明为“static final”,因为这样常量会被存放在dex文件的静态字段初始化器中被直接访问,否则在运行时需要通过编译时自动生成的一些函数来初始化。此规则只对基本类型和String类型有效。 不要将视图控件声明为static,因为View对象会引用Activity对象,当Activity退出时其对象本身无法被销毁,会造成内存溢出。
3. 避免内部的Getters/Setters
面向对象设计中,字段访问使用Getters/Setters通常是一个好的原则,但是在Android开发中限于硬件条件,除非字段需要被公开访问,否则如果只是有限范围内的内部访问(例如包内访问)则不建议使用Getters/Setters。在开启JIT时,直接访问的速度比间接访问要快7倍。
4. 使用增强for循环
优先使用增强for循环通常情况下会获得更高的效率;除了一种情况,即对ArrayList进行遍历时,使用普通的for循环效率要更高。
5. 使用package代替private以便私有内部类高效访问外部类成员
私有内部类的方法访问外部类的私有成员变量和方法,在语法上是正确的,但是虚拟机在运行时并不是直接访问的,而是在编译时会在外部类中自动生成一些包级别的静态方法,执行时内部类会调用这些静态方法来访问外部类的私有成员。这样的话就多了一层方法调用,性能有所损耗。 一种解决这个问题的方法就是将外部类的私有成员改为包级别的,这样内部类就可以直接访问,当然前提是设计上可接受。
6.合理使用浮点类型
在Android设备中浮点型大概比整型数据处理速度慢两倍,所以如果整型可以解决的问题就不要用浮点型。 另外,一些处理器有硬件乘法但是没有除法,这种情况下除法和取模运算是用软件实现的。为了提高效率,在写运算式时可以考虑将一些除法操作直接改写为乘法实现,例如将“x / 2”改写为“x * 0.5”。
7.采用****<merge>****优化布局层数;采用****<include>****来共享布局。
8.延时加载View. 采用ViewStub 避免一些不经常的视图长期被引用,占用内存.
9.移除Activity默认背景,提升activity加载速度。
如果确信在Activity中使用不透明的背景,那么可以移除Activity的默认背景。 在代码中:getWindow().setBackgroundDrawable(null); 也可以在styles样式文件中设置并在Manifest文件中配置
<style name="MyStyle" parent="AppTheme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@null</item>
</style>
10.cursor 的使用。 要注意管理好cursor,不要每次打开关闭cursor.因为打开关闭Cursor非常耗时。 不再使用的cursor要记得关闭(一般在finally语句块执行)。 有一种情况下,我们不能直接将Cursor关闭掉,这就是在CursorAdapter中应用的情况,但是注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭。
protected void onDestroy() {
if(mAdapter != null&& mAdapter.getCurosr() != null) {
mAdapter.getCursor().close();
}
super.onDestroy();
}
11.广播BroadCast动态注册时,记得要在调用者生命周期结束时unregisterReceiver,防止内存泄漏。
12.针对ListView的性能优化
item尽可能的减少使用控件和布局的层次;背景色与cacheColorHint设置相同颜色;ListView中item的布局至关重要,必须尽可能的减少使用的控件,布局。RelativeLayout是绝对的利器,通过它可以减少布局的层次。同时要尽可能的复用控件,这样可以减少ListView的内存使用,减少滑动时GC次数。ListView的背景色与cacheColorHint设置相同颜色,可以提高滑动时的渲染性能。ListView中getView是性能是关键,这里要尽可能的优化。getView方法中要重用view;getView方法中不能做复杂的逻辑计算,特别是数据库操作,否则会严重影响滑动时的性能;ListView数据项较多时考虑分页加载。
13.注意使用线程的同步机制(synchronized),防止多个线程同时访问一个对象时发生异常。
14.合理使用StringBuffer,StringBuilder,String
在简单的字符串拼接中,String的效率是最高的,例如String s = “hello” + “world”; 但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,例如: String str2 = “This is”; String str3 = “ a ”; String str4 = “ test”; String str1 = str2 +str3 + str4; 这里就要求使用StringBuilder了 在单线程中,StringBuilder的性能要比StringBuffer高。多线程为了线程安全需要采用StringBuffer,因为它是同步的。常规下一般用StringBuilder。
15. 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。
16.I/O流操作记得及时关闭流对象。
17.使用IntentService代替Service
IntentService和Service都是一个服务,区别在于IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent(在onHandleIntent方法中),对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程,如果有耗时的操作与其在Service里面开启新线程还不如使用IntentService来处理耗时操作。
18.使用Application Context代替Activity中的Context
不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的 对于生命周期长的对象,可以使用Application Context 不要把Context对象设置为静态。
19.集合中的对象要及时清理
我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
20.Bitmap的使用
较大的Bitmap注意压缩后再使用,加载高清大图可以考虑BitmapRegionDecoder的使用, 不再使用的Bitmap注意及时recycle().
21.巧妙的运用软引用(SoftRefrence)
有些时候,我们使用Bitmap后没有保留对它的引用,因此就无法调用Recycle函数。这时候巧妙的运用软引用,可以使Bitmap在内存快不足时得到有效的释放。有关Java引用机制的介绍可以看我的另一篇博客:http://blog.csdn.net/gs12software/article/details/51051813
22.尽量不要使用整张的大图作为资源文件,尽量使用9path图片
应用图标优先放在mipmap目录下(AndroidStudio环境),其他资源图,.9图应该放在drawable-xxxx下,需要复制到手机sd卡上使用的应放在asset目录
23.了解并使用库函数
Java标准库和Android Framework中包含了大量高效且健壮的库函数,很多函数还采用了native实现,通常情况下比我们用Java实现同样功能的代码的效率要高很多。所以善于使用系统库函数可以节省开发时间,并且也不容易出错。
24.关于WebView 在Activity或者Fragment销毁时记得把WebView也销毁
@Override
protected void onDestroy() {
if(webView!= null) {
webView.destroy();
webView= null;
}
super.onDestroy();
}
总结
性能优化是一个长期的工作,要结合项目具体场景具体优化
性能优化不是更新一两个版本就可以解决的,是持续性的需求,持续集成迭代反馈。在实际的项目中,在项目刚开始的时候,由于人力和项目完成时间限制,性能优化的优先级比较低,等进入项目投入使用阶段,就需要把优先级提高,但在项目初期,在设计架构方案时,性能优化的点也需要提早考虑进去,这就体现出一个程序员的技术功底了。
什么时候开始有性能优化的需求,往往都是从发现问题开始,然后分析问题原因及背景,进而寻找最优解决方案,最终解决问题,这也是日常工作中常会用到的处理方式。
我是阿耀:
有码走遍天下 无码寸步难行
1024 - 梦想,永不止步!
爱编程 不爱Bug
爱加班 不爱黑眼圈
固执 但不偏执
疯狂 但不疯癫
生活里的菜鸟
工作中的大神
身怀宝藏,一心憧憬星辰大海
追求极致,目标始于高山之巅
一群怀揣好奇,梦想改变世界的孩子
一群追日逐浪,正在改变世界的极客
你们用最美的语言,诠释着科技的力量
你们用极速的创新,引领着时代的变迁
------至所有正在努力奋斗的程序猿们!加油!!
网友评论