1、避免创建短命的临时对象。
减少对象的创建就能减少垃圾收集,进而减少对用户体验的影响。
案例:
(1)截取一段字符串时,尽量使用substring函数取得原始数据的一个子串,而不是为子串另外建立一份拷贝。
(2)多维数组分成多个一维数组
(3)int数组比Integer数组好,这也概括了一个基本事实,两个平行的int数组比 (int,int)对象数组性能要好很多
2、静态方法:
如果不需要访问某对象的字段,将方法设置为静态,调用会加速15%到20%。
3、 避免内部Getters/Setters
在公共接口中使用Getters和Setters是有道理的,
但在一个字段经常被访问的类中宜采用直接访问。
无JIT时,直接字段访问大约比调用getter访问快3倍。有JIT(编译器)时(直接访问字段开销等同于局部变量访问),要快7倍。
4、将成员缓存到本地
(1)访问成员变量比访问本地变量慢得多
一般代码:直接访问成员变量
for(int i =0; i <this.mCount; i++) {
dumpItem(this.mItems);
}
//改成访问本地变量:更快
//////转为本地变量:
int count = this.mCount;
Item[] items = this.mItems;
for(int i =0; i < count; i++) {
dumpItems(items);
}
(2)永远不要在for的第二个条件中调用任何方法:
for(int i =0; i < this.getCount(); i++) {}
(3)、同样如果你要多次访问一个变量,也最好先为它建立一个本地变量(方法的参数和本地变量一样)
一般的代码:
protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) {
if(isHorizontalScrollBarEnabled()) {
intsize = mScrollBar.getSize(false);
if(size <=0) {
size = mScrollBarSize;
}
mScrollBar.setBounds(0, height - size, width, height);
mScrollBar.setParams(computeHorizontalScrollRange(), computeHorizontalScrollOffset(), computeHorizontalScrollExtent(),false);
mScrollBar.draw(canvas);
}
}
//分析:
mScrollBar在方法中使用了四次,可以将他转换为本地变量!
5、 对常量使用static final修饰符
案例:
static int intVal = 42;
在编译过程中:
必以其会生成一个叫做clinit的初始化类的方法,当类第一次被使用的时候这个方法会被执行。方法会将42赋给intVal;
/改进:加上final:
—->
类不再需要clinit方法,因为在成员变量初始化的时候,会将常量直接保存到类文件中;
//分析:
将一个方法或类声明为final不会带来性能的提升,
但是会帮助编译器优化代码。
举例说,如果编译器知道一个getter方法不会被重载,那么编译器会对其采用内联调用。
5、改进的for循环语 法和迭代器具有相同的效率
在其他集合类中:
迭代器让接口调用 hasNext()和next()方法。在ArrayList中,手写的计数循环迭代要快3倍(无论有没有JIT)
for展示集中访问数组:
static class Foo {
int mSplat;
}
Foo[] mArray = ...
//每次循环都会访问两次静态成员变量,取得一次数组的长度。
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
//将所有成员变量存储到本地变量
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
//每次执行时会给a进行赋值
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
}
6、 避免使用浮点数
7、了解并使用类库
选择Library中的代码而非自己重写,除了通常的那些原因外,
考虑到系统空闲时会用汇编代码调用来替代library方法;
涉及到的场景:(c、c++实现的)
(1)String.indexOf(),String.lastIndexOf()等特殊实现的方法、System.arraycopy比循环快多了!
(2) android.text.format包下的Formatter类,
提供了IP地址转换、文件大小转换等方法;
DateFormat类,提供了各种时间转换,都是非常高效的方法
(3)、系统的TextUtils类
字符串处理Android为我们提供了一个简单实用的TextUtils类
(4)、高性能MemoryFile类
实现高性能的文件读写操作
/分析:
对于I/O需要频繁操作的,主要是和外部存储相关的I/O操作,MemoryFile通过将 NAND或SD卡上的文件,分段映射到内存中进行修改处理
8、合理利用本地方法
当你分配本地资源时 (本地堆上的内存,文件说明符等),往往很难实时的回收这些资源。
9、复杂算法尽量用C完成
复杂算法尽量用C或者C++完成,然后用JNI调用;
10、减少不必要的全局变量
尽量避免static成员变量引用资源耗费过多的实例,比如Context。
Android提供了很健全的消息传递机制(Intent)和任务模型(Handler),可以通过传递或事件的方式,防止一些不必要的全局变量。
11、资源的回收,不用过多指望gc:
Java的gc使用的是一个有向图,判断一个对象是否有效看的是其他的对象能到达这个对象的顶点
显示让系统回收:
if(bitmap.isRecycled()==false) { //如果没有回收
bitmap.recycle();
}
12、了解Java四种引用方式
强引用、软引用、弱引用和虚引用
13、使用实体类比接口好
//接口
Map map1 = new HashMap();
//接口
HashMap map2 = new HashMap();
14、避免使用枚举:
枚举变量非常方便,但不幸的是它会牺牲执行的速度和并大幅增加文件体积public class Foo {
public enum Shrubbery { GROUND, CRAWLING, HANGING }
}
/改进:
使用ordinal()方法获取枚举变量的整数值会更好一些:
int valX = MyEnum.VAL_X.ordinal();
int valY = MyEnum.VAL_Y.ordinal();
int count = list.size();
MyItem items = list.items();
for(int n =0; n < count; n++) {
intvalItem = items[n].e.ordinal();
if(valItem == valX) {
// do something
} else if(valItem == valY) {
// do something
}
}
15、在私有内部内中,考虑用包访问权限替代私有访问权限
public class Foo {
public class Inner {
public void stuff() {
Foo.this.doStuff(Foo.this.mValue);
}
}
private int mValue;
public void run() {
Inner in = new Inner();
mValue = 27;
in.stuff();
}
private void doStuff(int value) {
System.out.println("value:"+value);
}
}
//分析:
可以通过声明被内部类访问的字段和成员为包访问权限,而非私有。但这也意味着这些字段会被其他处于同一个包中的类访问,因此在公共API中不宜采用。
16、适量使用缓存:
17、关闭资源对象:
对SQLiteOpenHelper,SQLiteDatabase,Cursor,文件,I/O操作等都应该记得显示关闭。