Android学习——布局性能优化(高性能优化技巧)

布局性能优化(高性能优化技巧)

1.避免创建不必要的对象

下面来看一些我们可以避免创建对象的场景:

  • 1、如果我们有一个需要拼接的字符串,那么可以优先考虑使用StringBuffer或者StringBuilder来进行拼接。
  • 2、尽量使用基本数据类来代替封装数据类型,inttInteger要 更加高效,其它数据类型也是一样。
  • 3、如果我们明确地知道调用方会将这个返回的String再进行拼接操作的话,可以考虑返回一个StringBuffer对象来代替。
  • 4、基本数据类型要优于对象数据类型,类似地,
    基本数据类型的数组也要优于对象数据类型的数组。两个平行的数组要比一个封装好的对象数组更加高效,举个例子,Foo[]和Bar[]这样的两个数组,使用起来Custom(Foo,Bar)这样的一个数组高效得多。

我们所要遵守的一个基本原则就是尽可能地少创建临时对象,越少的对象意味着越少的GC操作,同时也就意味着越好的程序性能和用户体验。

2.静态优于抽象

如果你并不需要访问一个对象中的某些字段,只是想调用它的某个方法来去完成-项通用的功能,那么可以将这个方法设置成静态方法,这会让调用的速度提升15% 20%,同时也不用为了调用这个方法而去专门创建对象了,这样还满足了上面的一条原则。另外这也是一种好的编程习惯。 因为我们可以放心地调用静态方法,而不用担心调用这个方法后是否会改变对象的状态(静态方法内无法访问非静态字段)。

3.对常量使用static final修饰符

static int intVal = 42; static String strVal=“Hello, world!”;
骗译器会为上述代码生成-个初始化方法,称为< clinit>方法, 该方法会在定义类第一 次被使用的时候调用。然后这个方法会将38的值赋值到intVal当中, #从字符串常量表中提取一个引用赋值到strVal上。 当赋值完成后,我们就可以通过字段搜寻的
方式来去访问具体的值了。
static final int intVal = 42; static final String strVal = “Hello, world!” ;
修改之后,定义类不再需要< clinit>方法, 所有的常量都会在dex文件的初始化器中初始化。当调用intVal时可以直接指向42的值, 而调用strVal时会用一种相对轻量级的字符串常量方式,而不是字段搜寻的方式。

这种优化方式只对基本数据类型以及String类型的常量有效,对于其它数椐类型的常量是无效的。用static final声明常量是-种非常好的习惯。

4.避免在内部调用GettersSetters方法

在Android,上这个技巧就不再是那么的受推崇了,因为字段搜寻要比方法调用效率高得多,我们直接访问某个字段可能要比通过getters方法来去访问这个字段快3到7倍。

不过我们肯定不能仅仅因为效率的原因就将封装这个技巧给抛弃了,编写代码还是要按照面向对象思维的。

但是我们可以在能优化的地方进行优化,比如说避免在内部调用getters/setters方法。

5.使用增强的For循环语法

增强型for循环(他被称为for-each循环)可以用于去遍历实现Iterable接口的集合以及数组,用Collections,会构造一个Iterator接口去调用hasNext[]和next(),用一个Arraylist,手写计数循环要快3倍(有或没有JIT),但其他集合的增强的for循环的语法是完全等价的显式送代器的使用。

		//foreach
        int[] nums={1,2,3,4,5,6};
        for (int i:nums) {
            System.out.println(i);
        }
        
        //手写for
        int count=nums.length;
        for (int i = 0; i <count ; i++) {
            System.out.println(i);
        }

示例:

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+=mArray[i].mSplat;
        }
    }
	public void two(){
        int sum=0;
        for (Foo a:mArray) {
            sum+=a.mSplat;
        }
    }

三种方法的分析结果:
zero()方法是最慢, 因为它是把mArray. length写在循环当中的, 也就是说每循环- 次都需要重新计算- 次mArray的长度。
one()方法则相对快得多, 因为它使用了一个局部变量len来记录数组的长度,这样就省去了每次循环时字段搜寻的时间。
two()方法在没有JIT (Just In Time Compiler) 的设备上是运行最快的,而在有JIT的设备上运行效率和one()方法不相上下,唯一需要注意的是这种写法需要JDK 1.5之后才支持。
所以,在默认情况下,我们应该使用增强for, 但在遍历ArrayList时, 我们还是使用手写循环的方式。

6.考虑包而不是私有的内部类访问

看下面的代码:
在这里插入图片描述
在这里插入图片描述
可以通过声明被内部类访问的字段和成员为包访问权限,而非私有。但这也意味着这些字段会被其他处于同一个包中的类访问,因此在公共API中不宜采用。

7.避免使用浮点数

通常的经验是,在Android设 备中,浮点数会比整型慢2倍。
从速度方面说,在现代硬件上, float和double之间没有任何不同。 更广泛的讲,double大2倍。 在台式机上,由于不存在空间问题,double的优先 级高于float。
但即使是整型,有的芯片拥有硬件乘法。却缺少除法。这种情况下,整型除法和求模运算是通过软件实现的,就像当你设计Hash表,或是做大量的算术那样。

8.多使用系统封装好的API

系统的API在很多时候比我们自己写的代码要快得多,它们的很多功能都是通过底层的汇编模式执行的。
如果我们要实现一个数组拷贝的功能,使用循环的方式来对数组中的每-一个元素- -一进行赋值当然是可行的,但是如果我们直接使用系统中提供的System.arraycopy()方法将会让执行效率快9倍以上。

9.使用实现类比接口好

比如:

Map map1=new HashMap();
HashMap map2=new HashMap();

调用一个接口的引用会比调用实体类的引用多花一倍的时间。

10.将成员变量缓存到本地

访问成员变量比访问本地变量慢得多

for(int i=0;i<this.mCount;i++)dumpItem(this.mItems[i]);

再改成这样:

int count=this.mCount;
Item[] items=this.mItems;
for(int i=0;i<count;i++)dumpItem(items[i]);

(使用this是为了表明蛇蝎是成员变量)

另一个相似原则是:永远不要在for的第二个条件中调用任何方法。比如上面方法所示,在每次循环的时候都会调用getCount()方法,这样做比你在一个int先把结果保存起来开销大很多。
访问成员变量时,如果将它缓存到本地,成员变量的访问就会变成效率更高的栈变量访问。

猜你喜欢

转载自blog.csdn.net/UUUUUltraman/article/details/89522845
今日推荐