通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻 辑,但是性能不一定是最优化的。一般来说,优秀的程序员在写完代码之后都会不断的对代码进行重构。重构的好处有很多,其中一点,就是对代码进行优化,提高 软件的性能。下面我们就从几个方面来了解Android开发过程中的代码优化。

1)静态变量引起内存泄露
在 代码优化的过程中,我们需要对代码中的静态变量特别留意。静态变量是类相关的变量,它的生命周期是从这个类被声明,到这个类彻底被垃圾回收器回收才会被销 毁。所以,一般情况下,静态变量从所在的类被使用开始就要一直占用着内存空间,直到程序退出。如果不注意,静态变量引用了占用大量内存的资源,造成垃圾回 收器无法对内存进行回收,就可能造成内存的浪费。
先来看一段代码,这段代码定义了一个Activity。
private static Resources mResources;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
if (mResources == null) {
mResources = this.getResources();
}
}

这 段代码中有一个静态的Resources对象。代码片段mResources = this.getResources()对Resources对象进行了初始化。这时Resources对象拥有了当前Activity对象的引 用,Activity又引用了整个页面中所有的对象。
如果当 前的Activity被重新创建(比如横竖屏切换,默认情况下整个Activity会被重新创建),由于Resources引用了第一次创建的 Activity,就会导致第一次创建的Activity不能被垃圾回收器回收,从而导致第一次创建的Activity中的所有对象都不能被回收。这个时 候,一部分内存就浪费掉了。

经验分享:
在实际项目中,我们经常会把一些对象的引用加入到集合中,如果这个集合是静态的话,就需要特别注意了。当不需要某对象时,务必及时把它的引用从集合中清理掉。或者可以为集合提供一种更新策略,及时更新整个集合,这样可以保证集合的大小不超过某值,避免内存空间的浪费。

2)使用Application的Context
在 Android中,Application Context的生命周期和应用的生命周期一样长,而不是取决于某个Activity的生命周期。如果想保持一个长期生命的对象,并且这个对象需要一个 Context,就可以使用Application对象。可以通过调用Context.getApplicationContext()方法或者 Activity.getApplication()方法来获得Application对象。
依然拿上面的代码作为例子。可以将代码修改成下面的样子。
private static Resources mResources;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
if (mResources == null) {
// mResources = this.getResources();
mResources = this.getApplication().getResources();
}
}

在这里将this.getResources()修改为this.getApplication().getResources()。修改以 后,Resources对象拥有的是Application对象的引用。如果Activity被重新创建,第一次创建的Activity就可以被回收了。

3)及时关闭资源
Cursor 是Android查询数据后得到的一个管理数据集合的类。正常情况下,如果我们没有关闭它,系统会在回收它时进行关闭,但是这样的效率特别低。如果查询得 到的数据量较小时还好,如果Cursor的数据量非常大,特别是如果里面有Blob信息时,就可能出现内存问题。所以一定要及时关闭Cursor。
下面给出一个通用的使用Cursor的代码片段。
Cursor cursor = null;
try{
cursor = mContext.getContentResolver().query(uri,null,null,null,null);
if (cursor != null) {
cursor.moveToFirst();
// 处理数据
}
} catch (Exception e){
e.printStatckTrace();
} finally {
if (cursor != null){
cursor.close();
}
}

即对异常进行捕获,并且在finally中将cursor关闭。
同样的,在使用文件的时候,也要及时关闭。

4)使用Bitmap及时调用recycle()
前面的章节讲过,在不使用Bitmap对象时,需要调用recycle()释放内存,然后将它设置为null。虽然调用recycle()并不能保证立即释放占用的内存,但是可以加速Bitmap的内存的释放。
在代码优化的过程中,如果发现某个Activity用到了Bitmap对象,却没有显式的调用recycle()释放内存,则需要分析代码逻辑,增加相关代码,在不再使用Bitmap以后调用recycle()释放内存。

5)对Adapter进行优化
下面以构造ListView的BaseAdapter为例说明如何对Adapter进行优化。
在BaseAdapter类中提供了如下方法:
public View getView(int position, View convertView, ViewGroup parent)

当ListView列表里的每一项显示时,都会调用Adapter的getView方法返回一个View,
来向ListView提供所需要的View对象。
下面是一个完整的getView()方法的代码示例。
public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder;
if (convertView == null) {
   convertView = mInflater.inflate(R.layout.list_item, null);
   holder = new ViewHolder();
   holder.text = (TextView) convertView.findViewById(R.id.text);
   convertView.setTag(holder);
  } else {
   holder = (ViewHolder) convertView.getTag();
  }
  holder.text.setText("line" + position);
  return convertView;
}

private class ViewHolder {
  TextView text;
}

当 向上滚动ListView时,getView()方法会被反复调用。getView()的第二个参数convertView是被缓存起来的List条目中 的View对象。当ListView滑动的时候,getView可能会直接返回旧的convertView。这里使用了convertView和 ViewHolder,可以充分利用缓存,避免反复创建View对象和TextView对象。
如果ListView的条目只有几个,这种技巧并不能带来多少性能的提升。但是如果条目有几百甚至几千个,使用这种技巧只会创建几个convertView和ViewHolder(取决于当前界面能够显示的条目数),性能的差别就非常非常大了。

6)代码“微优化”
当今时代已经进入了“微时代”。这里的“微优化”指的是代码层面的细节优化,即不改动代码整体结构,不改变程序原有的逻辑。尽管Android使用的是Dalvik虚拟机,但是传统的Java方面的代码优化技巧在Android开发中也都是适用的。
下面简要列举一部分。因为一般Java开发者都能够理解,就不再做具体的代码说明。
创建新的对象都需要额外的内存空间,要尽量减少创建新的对象。
将类、变量、方法等等的可见性修改为最小。
针对字符串的拼接,使用StringBuffer替代String。
不要在循环当中声明临时变量,不要在循环中捕获异常。
如果对于线程安全没有要求,尽量使用线程不安全的集合对象。
使用集合对象,如果事先知道其大小,则可以在构造方法中设置初始大小。
文件读取操作需要使用缓存类,及时关闭文件。
慎用异常,使用异常会导致性能降低。
如果程序会频繁创建线程,则可以考虑使用线程池。

经验分享:
代 码的微优化有很多很多东西可以讲,小到一个变量的声明,大到一段算法。尤其在代码Review的过程中,可能会反复审查代码是否可以优化。不过我认为,代 码的微优化是非常耗费时间的,没有必要从头到尾将所有代码都优化一遍。开发者应该根据具体的业务逻辑去专门针对某部分代码做优化。比如应用中可能有一些方 法会被反复调用,那么这部分代码就值得专门做优化。其它的代码,需要开发者在写代码过程中去注意。

最新文章

  1. STM32F429 LCD程序移植
  2. C# DataGridView中指定的单元格不能编辑
  3. BZOJ 2438: [中山市选2011]杀人游戏
  4. OPPO某某產品拍攝範圍嶄露頭角
  5. java之接口interface
  6. 利用word2vec对关键词进行聚类
  7. Linux文件编程实例
  8. 换行word-wrap与word-break兼容IE和FIREFOX -----设计师零张
  9. SQL中的左连接与右连接有什么区别,点解返回值会不同?(转)
  10. Python For嵌套循环 图形打印X型 nested loop -练习题
  11. Course3-Python文件I/O
  12. PHP中生成UUID
  13. BugPhobia发布篇章:学霸在线系统测试报告
  14. 用PNChart绘制饼状图简介
  15. Linux中使用sendmail发送邮件,指定任意邮件发送人
  16. HDU 5723 Abandoned country(最小生成树+边两边点数)
  17. centos7 mysql+MHA高可用安装
  18. 《Nginx - 变量》- log_format/核心变量
  19. ecliplse java log4j 配置
  20. 26. Remove Duplicates from Sorted Array(删除排序数组中的重复元素,利用排序的特性,比较大小)

热门文章

  1. Vue2.0实现双向绑定的原理
  2. django 获取 POST 请求值的几种方法(转)
  3. Maven编译代码的相关命令
  4. 关于hessian接口类方法顺序及对象序列化的实战研究
  5. Linux使用jstat命令查看jvm的GC情况(转)
  6. windows10许可证即将过期怎么办
  7. 定制NSLog便于打印调试
  8. Easyui NumberBox格式化展示
  9. Jenkins自动部署到(远程)tomcat服务器
  10. calibre怎么转换文件格式