Android优化之优化Java代码

来源:互联网 发布:vue服务端渲染java 编辑:程序博客网 时间:2024/06/08 21:51

1、如果需要用很多对象时可以使用Cache,经常写Java的人可能会使用HashMap去实现Cache,但当Key是Integer的值时,Android为我们定义了一个更有效率的一个类:SparseArray类,它具有比HashMap更高的效率。

2、不同的API版本针对不同的功能已经做了优化,有些函数被弃用,启用新的调用函数,因此,在实现不同的API版本的时候,可针对不同的API进行不同程度的优化,个人觉得这种优化成本高,收益小。如:在HONEYCOMB中,sparseArray进行了优化,因此在使用高版本的sdk时,使用新的函数,对于低版本使用旧的兼容函数实现。

      

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {sparseArray.removeAt(1); // API level 11 and above} else {int key = sparseArray.keyAt(1); // 默认实现效率更低sparseArray.remove(key);}


3、性能并不仅仅指程序的执行速度,也包括用户交互体验,用户在使用软件时的响应速度等。ui线程用来处理按键消息(如:View.onKeyDown()或Activity.onKeyLongPress()),图形绘画(如:View.onDraw())以及生命周期时间的发生(如:onCreate(),onStart()等),其它不重要的代码尽量放到非ui线程去处理,避免出现ANR(Application Not Responding)的出现。

在Activity中,尽量减少Activity的启动时间是非常重要的,尽量减小在onCreate(),onStart(),onResume()中执行过于耗时的操作,如,Activeity的onCreate()方法中一般使用setContentView或者其它的方式去添加视图inflate视图,而inflate视图的过程是比较耗时的,因此UI界面的设计非常重要,在xml中,尽量使用简洁的布局可以减少布局的加载时间,有一些常用的操作,比如:

(1)使用RelativeLayout代替LinearLayout

(2)view的layout尽量使用viewroot去实现延迟加载,加快ui展示

具体详看我之前的文章:Tips from Android SDK Articles 


4、在针对网络和文件操作时应处理低网速及io操作的情况,sd卡有不同的处理速度,如果我们的程序很依赖于sd卡的性能,那就必须重点测试下不同厂家的sd卡
5、在2.3后可以使用StrictMode去辅助测试程序在低速率下或者其它情况下的用户体验和程序的健壮性,注意,这个仅在开发时使用,发布版本时必须去掉。举个例子如下:让你的代码执行的效率低点:

public static BigInteger computeRecursivelyWithCache(int n){StrictMode.noteSlowCall(“computeRecursivelyWithCache”); // message can beanythingSparseArray<BigInteger> cache = new SparseArray<BigInteger>();return computeRecursivelyWithCache(n, cache);}…}

6、数据库优化

我们在使用数据库的时候,经常会使用到CREATE TABLE, INSERT INTO语句等,举个例子:

SQLiteDatabase db = SQLiteDatabase.create(null); db.execSQL(“CREATE TABLE cheese (name TEXT, origin TEXT)”);db.execSQL(“INSERT INTO cheese VALUES (‘Roquefort’, ‘Roquefort-sur-Soulzon’)”);db.close(); 

执行SQLite语句的时候会花一定的时间,这些语句需要:解释或者编译或者执行而且而且String是不可变的,因此在构成该语句的时候,又进行了很多对象的创建操作,导致性能的问题。这里通过举个例子去详细讲解下:

public class Cheeses {private static final String[] sCheeseNames = {“Abbaye de Belloc”,“Abbaye du Mont des Cats”,…“Vieux Boulogne”};private static final String[] sCheeseOrigins = {“Notre-Dame de Belloc”,“Mont des Cats”,…“Boulogne-sur-Mer”};private final SQLiteDatabase db;public Cheeses () {db = SQLiteDatabase.create(null); // memory-backed databasedb.execSQL(“CREATE TABLE cheese (name TEXT, origin TEXT)”);}public void populateWithStringPlus () {int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];String sql = “INSERT INTO cheese VALUES(\”” + name + ”\”,\”” + origin +”\”)”;db.execSQL(sql);}}}
在执行populateWithStringPlus的时候,会创建大量的String对象以及执行execSQL。针对第一点,最明显的优化的手段就是少用String的+操作,使用String.format或者StringBuilder进行代替:
public void populateWithStringFormat () {int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];CHAPTER 1: Optimizing Java Code 27String sql = String.format(“INSERT INTO cheese VALUES(\”%s\”,\”%s\”)”, name,origin);db.execSQL(sql);}}public void populateWithStringBuilder () {StringBuilder builder = new StringBuilder();builder.append(“INSERT INTO cheese VALUES(\””);int resetLength = builder.length();int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];builder.setLength(resetLength); // reset positionbuilder.append(name).append(“\”,\””).append(origin).append(“\”)”); // chaincallsdb.execSQL(builder.toString());}}
当添加爱650条数据时,String.format花436ms的时候,而StringBuilder花了371ms,后者效率更佳,但不是很明显。

优化的第二个方法:因为每条插入语句都差不多,只不过数据有变化而已,因此可以使用compileStatement创建语句进行复用,在循环外仅编译一次语句:

public void populateWithCompileStatement () {SQLiteStatement stmt = db.compileStatement(“INSERT INTO cheese VALUES(?,?)”);int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];stmt.clearBindings();stmt.bindString(1, name); // replace first question mark with namestmt. bindString(2, origin); // replace second question mark with originstmt.executeInsert();}}
在该方法中,SQL语句仅编译一次,而无需编译650次,优化后的时间仅仅268ms

8、读取数据库时尽量只选取所需要的数据去读,不要全部都读

public void iterateBothColumns () {Cursor c = db.query(“cheese”, null, null, null, null, null, null);if (c.moveToFirst()) {do {} while (c.moveToNext());}c.close(); }public void iterateFirstColumn () {Cursor c = db.query(“cheese”, new String[]{“name”}, null, null, null, null, null); // 不一样的地方if (c.moveToFirst()) {do {} while (c.moveToNext());}c.close();}

如第一个方法读取所有数据,而第二个方法读取name的数据,后者的所花的时间比前者少。