最近看 Android应用性能优化一书,虽然有点老,但是大致上还是有进步的。
自从Android版本2.2之后加入JIT,明显加快了Dalvik字节码编译成本地代码的速度,当然这样还是远远无法跟IOS的编译速度进行对比的,毕竟多了一次编译解释嘛。这章主要描写JAVA的代码优化。
拿最简单的斐波那契数列做例子,一般我们的实现思路最简便是递归实现:
public static long computeReceursively (int n)
{
if( n>1 ) return computeReceursively( n - 2) + computeReceursively ( n - 1 ) ;
return n;
}
递归的效率和内存占用率太高于是我们做了以下的优化。
第一次优化:
public static long computeReceursively (int n)
{
if ( n > 1 ) {
long a = 0, b = 1 ;
do {
long tmp = b ;
b += a;
a = tmp;
} while (--n > 1 );
return b;
}
return n;
}
}
与刚开始的递归相比,这种迭代算法的复杂性稍微高了一点,但是因为他是线性的,所以性能更好。此次性能优化大概有一倍的时间节省。但是这里我们少考虑了一个情况,如果n大于long所能取到的最大数的时候代码就会内存溢出了,那么大家都知道long是64位的,可容纳的最大斐波那契数是第92项(我们这里不是讨论一般情况,而是尽极的思考)所以我们还要继续优化下去。java提供了一个BigInteger类,这个类的对象可以容纳任意大小的有符号整数。数据类型的问题解决了又会带出运算速度的问题,这里给出的思路是引入Android自带的LruCache类(缓存)。下面是BigInteger+LruCache的实现:
public static BigInteger computeRecursivelyWithCache ( int n ){
int maxSize = 4 * 8 * 1024 *1024;//32兆
LruCache<Integer,BigInteger> cache = new LruCache<Integer,BigInteger>(maxSize);
return computeRecursivelyWithCache(n,cache);
}
private static BigInteger computeRecursivelyWithCache(int n, LruCache<Integer,BigInteger> cache){
if(n > 92 ){
BigInteger fN = cache.get(n);
if(fN == null) {
int m = (n/2) + (n & 1);
BigInteger fM = computeRecursivelyWithCache(m,cache);
BigInteger fM_1 = computeRecursivelyWithCache(m-1,cache);
if((n & 1) == 1){
fN = fM.pow(2).add(fM_1.pow(2));
}else{
fN = fM_1.shiftLeft(1).add(fM).multiply(fM);
}
cache.put(n,fN);
}
return fN;
}
return BigInteger.valueOf(iterativeFaster(n));
}
private static long iterativeFaster( int n ){
if (n >1 ){
long a , b = 1 ;
n--;
a = n & 1;
n/=2;
while (n-- > 0 ){
a +=b;
b +=a;
}
return b;
}
return n;
}
}
从这个优化思路上来看,我们还可以衍生出更多的优化,如仿CPU的做个2级缓存,把数据流大的数据放在二级缓存里面,一级缓存用作即读即用等。上述这个实现的性能区别于maxSize的大小,越大越快,然而,内存使用量可能会成为新的问题,所以作为开发人员,我们有责任选用最恰当的实现,比如N<92的时候采用递归实现,n>92的时候采用缓存实现。我们选用的方法不一定是最好的但是一定要是最合适的。
末尾说几点写APP布局的时候可以注意的方面:
1.尽量使用RelativeLayout代替LinearLayout,尽可能的保持“扁平化布局”。
2.尽量减少对象的创建,尤其是占用内存大的对象,不用的时候尽量在Activity的生命周期内释放掉(别把所有的初始化都放在OnCreate,用到的时候再初始化,减少界面的响应时间)。
3.使用ViewStub推迟对象的创建。
以上内容是我看第一章的总结,接下来的第二和第三章描写的是NDK的使用和JNI的调用 里面包含了一系列的JNI特有方法。但是想要更加高效的编程下面涉及到针对CPU寄存器的编程,使用汇编指令来优化算法,自我感觉没有接触到大数据的时候日常代码根本用不上,什么本地Activity啊,不同的CPU架构之间的指令数据流特殊编程等等等等我也就是浏览了一下做个记录,没打算深入研究过,所以现在对NDK的使用在APP的时候能做到哪些高效的优化仍然没有具体的概念。