当前位置: 首页 > 科技观察

Android性能优化:如何避免在Android中创建不必要的对象

时间:2023-03-22 13:36:50 科技观察

在编程开发中,内存占用是我们经常面临的现实。内存调整的通常方向是最小化内存使用。避免创建不必要的对象是其中的一个重要方面。Android设备不像PC那样内存充足,单个App占用的内存其实比较小。所以避免创建不必要的对象对于Android开发尤为重要。本文将介绍一些避免创建对象的常见场景和方法,有的是微优化,有的是编码技巧,当然也有真正能起到显着效果的方法。使用singletonsingleton是我们常用的设计模式。使用这种模式,我们只能提供一个对象进行全局调用。所以单例是一种避免创建不必要对象的方法。单例模式上手容易,但需要注意的问题很多。最重要的是在多线程并发的情况下保证单例的唯一性。当然还有很多方式,饿了么中国式,懒人式double-check等等,这里介绍一个很geek的单例写法。publicstaticclassSingleInstance{privateSingleInstance(){}publicstaticSingleInstancegetInstance(){returnSingleInstanceHolder.sInstance;}privatestaticclassSingleInstanceHolder{privatestaticSingleInstancesInstance=newSingleInstance();}}在Java中,类的静态初始化会在类加载时触发,我们可以利用这个原理,这个特性,结合内部类,可以实现上面的代码,以惰性方式创建实例。AvoidImplicitBoxingAutoboxing是Java5引入的特性,自动将原始类型的数据转换为对应的引用类型,比如将int转换为Integer。此功能大大减少了编码的琐碎工作,但如果不小心,可能会创建不必要的对象。比如下面的代码Integersum=0;for(inti=1000;i<5000;i++){sum+=i;}上面的代码sum+=i可以看做sum=sum+i,但是+运算符不是应用于Integer对象,首先sum进行自动拆箱操作,进行数值加法操作,最后进行自动装箱操作,转化为Integer对象。其内部变化如下:intresult=sum.intValue()+i;整数和=新整数(结果);由于我们这里声明的sum是Integer类型的,所以上面的循环会创建近4000个无用的Integer对象。在这样一个巨大的循环中,会降低程序的性能,增加垃圾回收的工作量。因此,我们在编程时需要注意这一点,正确声明变量类型,避免自动装箱带来的性能问题。另外,当原始数据类型的值加入到集合中时,也会发生自动装箱,所以这个过程中也有对象的创建。如果需要避免这种情况,可以选择SparseArray、SparseBooleanArray、SparseLongArray等容器。谨慎选择容器Java和Android提供了许多可编辑的容器集合来组织对象。如ArrayList、ContentValues、HashMap等。但是,这样的容器虽然使用起来方便,但是也存在一些问题,就是会自动扩容,并没有创建新的对象,而是创建了一个更大的容器对象。这意味着它将占用更多的内存空间。以HashMap为例,当我们放入key和value时,它会检查是否需要扩容,如果需要,进行二次扩容@OverridepublicVput(Kkey,Vvalue){if(key==null){returnputValueForNullKey(value);}//somecodehere//Noentryfor(non-null)keyispresent;createonemodCount++;if(size++>threshold){tab=doubleCapacity();index=hash&(tab.length-1);}addNewEntry(key,value,hash,index);returnnull;}关于扩容问题,通常有以下几种方法,预估一个更大的容量值,避免多次扩容寻找替代数据结构,保证时间和空间的平衡。善用LaunchMode。其中提到LaunchMode必须与Activity相关。一般情况下,我们在manifest中声明Activity。如果未设置LaunchMode,将使用默认的标准模式。一旦设置为标准,每次发出Intent请求时,都会创建一个新的Activity实例。例如,如果有10个用于撰写电子邮件的Intent,那么将创建10个ComposeMailActivity实例来处理这些Intent。事实证明,这种模式创建了一个Activity的多个实例。对于一个带有搜索功能的Activity,只保留一个Activity实例就够了。使用标准模式会导致创建过多的Activity实例,这样不好。合理使用LaunchMode,减少常识下Activity的创建。Activity处理onConfigurationChanged,这个跟Activity对象的创建有关,因为Activity的创建成本比其他对象高很多。默认情况下,当我们旋转屏幕时,原来的Activity会被销毁,并会创建一个新的Activity。这样做的原因是为了处理布局适配。当然,这是系统默认的做法。当我们的开发是可控的时候,我们就可以避免重新创建Activity。以屏幕切换为例,声明Activity时添加然后重写Activity的onConfigurationChanged方法@OverridepublicvoidonConfigurationChanged(ConfigurationnewConfig){super.onConfigurationChanged(newConfig);if(newConfig.orientation==Configuration.ORIENTATION_PORTRAIT){setContentView(R.layout.portrait_layout);}elseif(newConfig.orient==Configuration.ORIENTATION_LANDSCAPE){setContentView(R.layout.landscape_layout);}}注意字符串拼接,这可能是最不起眼的一项。这里主要是字符串拼接Log.i(LOGTAG,"onCreatebundle="+savedInstanceState);这应该是我们最常用的日志方式,但是内部的字符串拼接其实是生成了StringBuilder对象,然后一个一个的进行append,直到最后调用toString方法的过程。下面是一段代码循环的代码,显然是非常糟糕的,因为它创建了很多StringBuilder对象。publicvoidimplicitUseStringBuilder(String[]values){Stringresult="";for(inti=0;i

最新推荐
猜你喜欢