程序员在开发过程中,提高android程序运行效率应当注意的事项

1 介绍

无论开发什么产品,效率都是最重要的,安卓程序的效率也一样,如果你做出一款登录很慢,延时很长的产品,相信很多人都不愿意再打开,可能直接就删除了。

那么如何提高Android程序的运行效率,也就是说如何来优化Android的性能呢?下面提供给你一些想法,希望能够给广大安卓开发者带来灵感:

在程序的开发过程中,为节省系统资源,有两条基本的原则:

(1)开发过程中,你只实现你所需要的功能;

(2) 能避免占用内存时,就一定不要去占用内存;

以下所应注意的事项都是基于这两条原则上的。

也许有些人会提出,基于此原则将很难达到真正目的的优化。但我们也必须承认,在像开发手机这样的嵌入式设备上,有时,我们没有其它的选择,为了有一些小的优化,很难开发出高效的数据结构和算法的。例如,当你把你的想法在 android的模拟器上来进行实现时,你有可能因为没有注意,写得代码是以耗尽系统几乎所有内存为代价的.当你把程序上传到真机上时,此时,你的程序将运行的效率很低,很难达到用户的要求。

所以,下面要介绍的一些事项能够,它可以在程序开发中,指导我们的编码,只有这样,程序才能安全执行,运行效率才能提高。

2. 避免创建对象

对象的创建都是要占用资源的,如果你在循环程序中创建对象,由于过多的占用内存,你将定时的启动内容回收机制,从而降低了运行速度。

所以,当你不需要时,你应该避免创建类实例,给出以下几个例子作为说明:

尽量避免使用字符串,例如:从JSP或是其他客户端得到某些信息,其中包含int,Date,String类型,尽早把它们转化为自己合适的数据类型。

必须使用字符串时,考虑 当字符串不可变化时,使用String类型;当可变时使用StringBuffer类型。

当需要字符串+时,使用StringBuffer。这些例子大家可以在“动态对象管理”的DAO实现类中找到。

String s = “aaa” + “bbb”;

上面的语句实际上创建了三个String对象,性能受损。

StringBuffer s= new StringBuffer();

s.append(“aaa”);

s.append(“bbb”);

上面仅仅创建一个对象。

3. 多使用原始的方法

当处理字符串时,应该多的使用像String.indexOf(),String.lastIndex(),以及与它们同等的方法。

4 Prefer virtual over interface

当你要声明一个HashMap对象时,你可以声明它为一个HashMap类,或一个Map 类:

Map myMap1 = new HashMap(); HashMap myMap2 = new HashMap();

哪一个更好的呢?

在Pc机编程中,你应该更倾向与声明为Map,因为你可以调用Map中提供的接口来实现更多的功能。但是在手机开发中,通过此种方法的调用,比直接调用方法多花费一倍多的时间。所以,当你用HashMap类,而且它满足自己的需要,就不需要用声明为Map的方法。

5 避免在类内部进行Getters/Setters

在C++语言中,经常使用getters(eg. i=getCount())而不用局部变量的形式(i=mCount).在C++中这是一个很好的习惯,因为编译器可以通过内联进入getters。

但是在Android中,此习惯是不好的,因为调用虚拟机的代价很高,比直接使用局部变量费时的多.所以,在公共的接口中定义getters、setters是可取的,当时,在类中,你应该直接通过局部变量来访问。

如:

for (int i = 0; i < this.getCount();i++)

dumpItem(mItems[i]);

应该写为:

int mCount = this.getCount();

for (int i = 0; i < mCount; i++)

dumpItems(items[i]);

6. 静态成员优于非静态的

在编写程序过程中,因为静态成员的访问不需要构建类的实例。例如,QuyuDAOFactory的getDAO()方法,直接从类进行访问即可。

7 .精确数据计算时,不要使用float或是double类型

使用int或是long进行精确数据计算,自己管理小数位。
当数目不超过9位时,使用int类型;当数目不超过18位时,使用long;如果超过了18位,使用BigDecimal(注意它是对象,不是基本数据类型)。

8. 避免创建重复对象

Strings= new String(“guojun”);//永远不要这么干!
Strongs = “guojun”;//可以接受的改进

9.组合优于继承

当确实需要继承时才采用继承,否则使用类组合来完成。

10.接口优于抽象类

两种机制最明显的区别是抽象类容许包含某些方法的实现,而接口不行。

如:com.zte.resmaster.helpers.AbstractDAOImpl,就是抽象类,它具有得到数据库连接和清除数据库资源的方法,但是怎么实现具体的DAO操作必须是其子类实现。

如果设计成抽象类,一旦子类要求继承其他类时就没有办法实现,因为Java中不能多重继承(extends),但是可以多重实现(implements)。换句话说就是接口是定义混合类型的理想选择。

接口允许非层次类型框架的构造。

接口通过封装类方式,能够获得安全、强大的功能。

当然抽象类有另一个优势:改进抽象类比改进接口更加容易。一旦某个方法的实现发生了变化,仅仅需要更改一个地方;当新加一个方法时,所有子类都具有了该方法。

11. 尽量使用内部类

如果该类仅仅在某个调用者使用,那么把它设计成调用者的内部类。具体的例子,参见:com.zte.resmaster.system.rescomp.dao.RescompDAOOracle。不会暴露该内部类,避免滥用而导致的维护问题。

12. 最小化局部变量的作用域

最小化局部变量最有效的方法是在它第一次使用时声明。

几乎每个局部变量声明都应该包含一个初始值,否则编译也通不过。

方法小而集中,每个方法仅仅处理一种活动。

13. 了解和使用库

Java提供了强大而复杂的类库,在完成某个常用功能之前,看看Java类库中是否已经存在类似功能的类库。一方面减少工作量,一方面使得自己的程序更加简洁高效。

例如:向量(Collection,Set,List…)中字符串的排序:Collections.sort(v);

忽略大小写的排序:Collections.sort(v,String.CASE_INSENSITIVE_ORDER)

还有许多实用类库。

14. 通过接口访问对象

如果存在合适的接口类型,那么参数、返回值、变量和域应该用接口类型声明。

如果没有合适的接口,那么通过类而不是接口访问对象,是完全合适的。

15. 接口优于反射

失去在编译期间进行类型检查提供的好处。

代码笨拙而冗长。

性能损失。反射比正常的方法调用慢40倍左右(JDK1.3)。

有的时候,付出代价是值得的,因为能够得到更多的益处;一般而言,可以通过反射创建一个实例,然后通过他们的接口或是超类正常访问他们。

例如:DAO的Factory设计模式中的通过配置实现数据库实现类的平滑移植。

16. 实现功能后在想如何优化是一个比较好的策略。

17. 遵循普遍接受的命名规则。

18. http用gzip压缩,设置连接超时时间和响应超时时间

http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读。

19. 使用线程池,分为核心线程池和普通线程池,下载图片等耗时任务放置在普通线程池,避免耗时任务阻塞线程池后,导致所有异步任务都必须等待

20. listview 性能优化

  • 1).异步加载图片

item中如果包含有webimage,那么最好异步加载

  • 2).快速滑动时不显示图片

当快速滑动列表时(SCROLL_STATE_FLING),item中的图片或获取需要消耗资源的view,可以不显示出来;而处于其他两种状态(SCROLL_STATE_IDLE 和SCROLL_STATE_TOUCH_SCROLL),则将那些view显示出来

  • 3).复用convertView

在getItemView中,判断convertView是否为空,如果不为空,可复用。如果couvertview中的view需要添加listerner,代码一定要在if(convertView==null){}之外。

  • 4).BaseAdapter避免内存溢出

如果BaseAdapter的实体类有属性非常消耗内存,可以将保存到文件;为提高性能,可以进行缓存,并限制缓存大小。

21.尽量避免static成员变量引用资源耗费过多的实例,比如Context

22.异步任务,分为核心任务和普通任务,只有核心任务中出现的系统级错误才会报错,异步任务的ui操作需要判断原activity是否处于激活状态

23.保证Cursor 占用的内存被及时的释放掉,而不是等待GC来处理。并且 Android明显是倾向于编 程者手动的将Cursor close掉

24.线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程 生命周期的不可控

25.使用WeakReference代替强引用,弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存。

对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必要时回收时,可以考虑使用弱引用。

26.超级大胖子Bitmap及时的销毁(Activity的onDestroy时将bitmap回收

在被UI组件使用后马上进行回收会抛 RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap)设置一定的采样率(有开发者提供的图片无需进行采样,对于有用户上传或第三方的大小不可控图片,可进行采样减少图片所占的内存),从服务端返回图片,建议同时反馈图片的size巧妙的运用软引用drawable对应resid的资源,bitmap对应其他资源任何类型的图片,如果获取不到(例如文件不存在,或者读取文件时跑OutOfMemory异常),应该有对应的默认图片(默认图片放在在apk中,通过resid获取);

27.Drawable中ui组件需要用到的图片是apk包自带的,那么一律用setImageResource或者setBackgroundResource,而不要根据resourceid

注意:get(getResources(), R.drawable.btn_achievement_normal)该方法通过resid转换为drawable,需要考虑回收的问题,如果drawable是对象私有对象,在对象销毁前是肯定不会释放内存的。

28.复用、回收Activity对象临时的activity及时finish主界面设置为singleTask一般界面设置为singleTop

29.如果ImageView的图片是来自网络,进行异步加载

30.应用开发中自定义View的时候,交互部分,千万不要写成线程不断刷新界面显示,而是根据TouchListener事件主动触发界面的更新

31.在onResume时设置该界面的电源管理,在onPause时取消设置

32.位置信息获取用户的地理位置信息时,在需要获取数据的时候打开GPS,之后及时关闭掉

备注:这里所说的是一些事项,它们不是真理。大家在开发的过程发现自己会了解更多,望大家对该文档能提出批评意见或是补充。

此条目发表在 安卓开发 分类目录,贴了 , , , , , , , , , , 标签。将固定链接加入收藏夹。

发表评论