Android性能优化老生常谈,优化点比较宽泛和复杂,不同类型的项目优化点也不相同。但是可以规划为若干个点,总有一点适合你。
应用层的性能优化通常可以从以下几个方面考虑
1.界面布局优化(merge ,include ,ViewStub,减少布局嵌套层次);
merge可进行多余嵌套层次的移除处理,include复用同一布局在多个界面中 ,ViewStub可进行隐藏布局的不加载。
2. 采用合理的数据结构和算法提高程序性能,这往往是决定程序性能的关键;
程序设计上注意内存和CPU运算的性能。
3. 合理配置数据库缓存类型和优化SQL语句加快读取速度,使用事务加快写入速度;
优化sql查询不管是后端还是前端都应该注意的内容,大量数据读取和更新建议开启事务操作,提升性能和速度的效果比较明显。
同样操作5000条数据。开启事务与不开启事务对比。添加事务处理,把5000条插入作为一个事务
dataBase.beginTransaction(); //手动设置开始事务
//数据插入操作循环
dataBase.setTransactionSuccessful(); //设置事务处理成功,不设置会自动回滚不提交//这个之间不可以做事务操作.
dataBase.endTransaction(); //处理完成
db.execSQL("insert into user values(4,'张三2')");
db.execSQL("insert into user values(4,'李四2')");
db.execSQL("insert into user values(4,'王五2')");
db.execSQL("insert into user values(4,'赵六2')");
db.beginTransaction();// 开启事物
long time1 = System.currentTimeMillis();
try {
db.execSQL("insert into user values(1,'张三')");
db.execSQL("insert into user values(2,'李四')");
db.execSQL("insert into user values(3,'王五')");
db.execSQL("insert into user values(4,'赵六')");
db.setTransactionSuccessful();
} catch (SQLException e) {
e.printStackTrace();
db.endTransaction();}
db.endTransaction();
long time2 = System.currentTimeMillis();System.out.println("消耗时间:" + (time2 - time1));
消耗时间:4或10等等.
而去掉事务执行结果:
消耗时间:76或128等等.
4. 采用多线程、缓存数据、延迟加载、提前加载等手段优化操作;
凡是操作数据量略大的都应该采用多线程处理,重复数据应该进行缓存,加载数据弹出loading可进行延迟处理。
5. 尽量使用系统方法,提升效率,除非明显发现系统方法缺陷;
系统提供的API方法往往优于自定义方法,使用上也多数更加简便。比如:
系统提供的字符串比较方法TextUtils.equals()已经考虑到了字符串为null的情况,不会由于前置字符串为null造成崩溃。同理:TextUtils.isEmpty()方法、ArrayList.subList()方法。感兴趣的可以研究一下系统提供的工具方法。性能上比我们自己写的方法要好很多。
6. 合理释放资源(流的关闭,cursor,bitmap等).
如图所示的数据库查询操作中表面上看来没有什么问题,但是循环查询了若干次,每次采用一个cursor对象,但是实质上是一个cursor对象指向不同的地址,由于每次查询都是返回新的cursor对象,最后只关闭了一个cursor对象,所以会在造成许多cursor对象的未关闭,耗费性能。所以在操作数据库的时候尽量用一次cursor就跟着关闭一次cursor。对于流的操作也是如此。在一些流资源、数据库操作资源和一些耗内存的资源上,比如流、cursor、bitmap。这些资源的使用上需要多注意。使用之后及时释放。如果是频繁使用的场景下可能频繁申请和释放也比较耗费资源,可以考虑用资源池等手段处理。
7.使用工具分析性能问题,找出性能瓶颈;
写出高效的代码需要遵循两条原则:1,不执行不必要的操作; 2,不分配不必要的内存
一个程序员的代码约束
1.避免创建不必要的对象
每创建一个对象系统就会在堆内存申请一块儿空间。大量申请内存会造成OOM。如果对于一个操作可以用一个对象完成尽量不要申请多余的对象,即便对象不再使用的时候虚拟机会进行回收,但也造成了资源的多于占用。
2. 合理使用static成员
staitc成员的特殊性能简化许多操作,但是使用上千万注意内存泄露的问题。
最经典的内存泄漏情况就是Static成员引用Activity。
public class MainActivity extends Activity{
public static Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
}
}
public class MainActivity extends Activity{
public static Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
}
}
在这种情况下Context对象为静态的,那么Activity就无法正常的销毁,常驻内存,造成内存泄漏。
3. 使用增强for循环 (除了ArrayList)
4.使用package代替private以便私有内部类高效访问外部类成员
5.合理使用浮点类型(在Android设备中浮点型大概比整型数据处理速度慢两倍,所以如果整型可以解决的问题就不要用浮点型)
计算机在处理数据上是没有除法的这个定义的,除法操作都是一律转换为乘法进行处理,所以在计算的时候将/2这样的操作转化为*0.5这样的写法效率更高。
6,合理使用位运算替换乘除法数据在计算机中都是2进制存储,也就是010101的方式存储,这样2的整数倍的乘除法操作就可以通过位运算移位进行处理,这种方式是速度最快的,效率最高。
如图所示:同样处理1000条数据,将每一个数除以2,除法方式用了254毫秒,乘法用了88毫秒,位运算用了51毫秒。
7.采用优化布局层数, 采用
8.延时加载View. 采用ViewStub 避免一些不经常的视图长期被引用,占用内存.
9.移除无用背景,避免同一区域多次重绘,例如移除Activity默认背景,提升activity加载速度。
10.流相关资源,cursor 使用完毕及时关闭。
11.BroadCast动态注册时,记得要在调用者生命周期结束时unregisterReceiver,防止内存泄漏
12.针对ListView的性能优化,或者采用RecyclerView,类似思想复用思想也能应用到项目中
13.合理使用StringBuffer,StringBuilder,String
14.尽量使用局部变量
局部变量在应用上速度会比全局变量要快很多。
如图:同样操作1000次的循环全局变量7毫秒,局部变量3毫秒。
15. Context的使用注意点(尽量使用application这个变量值)
尽量使用Application的Context替代Activity的Context
16. 集合中的无用数据及时清除
集合中的数据占用的是堆内存,如果无用数据的集合还存在引用系统是无法回收的,所以无用的集合内数据要及时清除掉,释放资源。
17.较大bitmap压缩后使用,使用完成在合适的时候回收,采用三方框架显示图片
18.尽量不要使用整张的大图作为背景,采用.9图片充当背景
19.了解使用库函数和系统自带函数
20.再Activity和Fragment中使用webview,及得将其置空
以上知识点总结如下:
布局优化尽量不存在冗余嵌套及过于复杂布局,尽量使用GONE替换INVISIBLE,使用weight后尽量将width和heigh设置为0dp减少运算,Item存在非常复杂的嵌套时考虑使用自定义View来取代,减少measure与layout次数等。列表及Adapter优化;尽量复用getView方法中的相关View,不重复获取实例导致卡顿,列表尽量在滑动过程中不进行UI元素刷新等。背景和图片等内存分配优化;尽量减少不必要的背景设置,图片尽量压缩处理显示,尽量避免频繁内存抖动等问题出现。自定义View等绘图与布局优化;尽量避免在draw、measure、layout中做过于耗时及耗内存操作,尤其是draw方法中,尽量减少draw、measure、layout等执行次数。
性能检测工具
从应用上和开发上注意细节尽量提升应用的性能。但是有的时候没有注意到而造成了应用的性能出现问题,比如卡顿、占内存比较高。这时候直接从代码上查找问题不太方便。这时候就需要性能分析工具帮助我们来完成。主要说几种常见的性能分析工具,包括一些简单的使用,和性能分析结果图的查看。
1.Hierarchyviewer.bat检测View的冗余程度,复杂程度,渲染时间。
Hierarchyviewer.bat在最新的AS版本上不支持真机调试,所以可用性不是太高。这个工具主要是来进行ViewTree层级的分析,可以查看View的嵌套层级,直观的看出有没有多余的嵌套。
这张图片摘自于网上,从图中可以看出一个界面的View嵌套等级,如果同一个方向节点由多余的嵌套,可以直观的看出来。
2. Lint布局和资源文件优化工具
Lint布局和资源分析工具主要检测项目中的无用资源 和引用。包括布局文件中的常量字符串。如果这种字符串没有采用@stirng方式引用的话都会被找出来。Google是不建议这种硬编码的。
3. TraceView性能分析优化
TraceView是AndoridStudio自带的性能分析工具,可以分析出你指定操作流程的花费时间,每个函数的调用次数,CPU占用时间等等。真机运行App,打开DDMS。如图所示:
从下图中可以看出每一个函数调用占用此流程CPU的百分比,占用的真实时间,调用次数,重复调用次数等。
拿diapatchMessage方法来说,如图所示:此方法占用了62.5%的CPU时间,真实花费时间1638.315毫秒,调用次数19次。所以如果开发中的某一个界面调用比较卡顿的情况就可以来进行分析一下,看看占用时间比较多的操作是什么。该怎么进行优化,减少调用时间,减少调用次数。