Android应用性能优化基础知识。
布局优化
- 避免OverDraw过渡绘制
- 优化布局层级
- 避免嵌套过多无用布局
- 当我们在画布局的时候,如果能实现相同的功能,优先考虑相对布局,然后在考虑别的布局,不要用绝对布局。
- 使用
<include />
标签把复杂的界面需要抽取出来 - 使用
<merge />
标签,因为它在优化UI结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个Android Layout的结构。核心功能就是减少冗余的层次从而达到优化UI的目的! - ViewStub 是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。
Android布局优化之Merge Include ViewStub使用与源码分析
Android抽象布局——include、merge 、ViewStub
Android LayoutInflater原理分析,带你一步步深入了解View(一)
代码优化
- 使用AndroidLint分析结果进行相应优化
- 不使用枚举及IOC框架,反射性能低
- 常量加static
- 静态方法
- 减少不必要的对象、成员变量
- 尽量使用线程池
- 适当使用软引用和弱引用
- 尽量使用静态内部类,避免潜在的内存泄露
- 图片缓存,采用内存缓存LRUCache和硬盘缓存DiskLRUCache
- Bitmap优化,采用适当分辨率大小并及时回收
ListView和GridView优化
- 采用ViewHolder复用convertView
- 避免在getView中执行耗时操作
- 列表在滑动状态时不加载图片
- 开启硬件加速
移动端获取网络数据优化
- 连接复用 :节省连接建立时间,如开启 keep-alive。
对于 Android 来说默认情况下 HttpURLConnection 和 HttpClient 都开启了 keep-alive。只是 2.2 之前 HttpURLConnection 存在影响连接池的 Bug,具体可见:Android HttpURLConnection 及 HttpClient 选择 - 请求合并:即将多个请求合并为一个进行请求,比较常见的就是网页中的 CSS Image Sprites。如果某个页面内请求过多,也可以考虑做一定的请求合并。
- 减少请求数据的大小:对于post请求,body可以做gzip压缩的,header也可以作数据压缩(不过只支持http 2.0)。
返回的数据的body也可以作gzip压缩,body数据体积可以缩小到原来的30%左右。(也可以考虑压缩返回的json数据的key数据的体积,尤其是针对返回数据格式变化不大的情况,支付宝聊天返回的数据用到了) - 根据用户的当前的网络质量来判断下载什么质量的图片(电商用的比较多)。
相关工具
- 使用Hierarchy Viewer查看UI布局层级
- 使用AndroidStudio Memory Monitor查看内存使用情况
- 使用TraceView优化App性能
- 使用内存泄露分析工具MAT分析APP内存状态
- 检测内存泄露的开源库:LeakCanary
- 腾讯出品:GT
Android中引起内存泄露的原因
内存泄漏简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。
- 注册没取消造成内存泄露,如:广播
- 静态变量持有Activity的引用
- 单例模式持有Activity的引用
- 查询数据库后没有关闭游标cursor
- 构造Adapter时,没有使用 convertView 重用
- Bitmap对象不在使用时调用recycle()释放内存
- 对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放
- 使用Handler造成的内存泄露
Android中使用Handler造成的内存泄露解决方案
- 静态内部类+弱引用WeakReference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class HandlerActivity2 extends Activity { private static final int MESSAGE_1 = 1; private static final int MESSAGE_2 = 2; private static final int MESSAGE_3 = 3; private final Handler mHandler = new MyHandler(this); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler.sendMessageDelayed(Message.obtain(), 60000); // just finish this activity finish(); } public void todo() { }; private static class MyHandler extends Handler { private final WeakReference<HandlerActivity2> mActivity; public MyHandler(HandlerActivity2 activity) { mActivity = new WeakReference<HandlerActivity2>(activity); } @Override public void handleMessage(Message msg) { System.out.println(msg); if (mActivity.get() == null) { return; } mActivity.get().todo(); } } |
进一步优化
当Activity finish后 handler对象还是在Message中排队。 还是会处理消息,这些处理有必要?
正常Activitiy finish后,已经没有必要对消息处理,那需要怎么做呢?
解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。
通过查看Handler的API,它有几个方法:removeCallbacks(Runnable r)和removeMessages(int what)等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * 一切都是为了不要让mHandler拖泥带水 */ @Override public void onDestroy() { mHandler.removeMessages(MESSAGE_1); mHandler.removeMessages(MESSAGE_2); mHandler.removeMessages(MESSAGE_3); // ... ... mHandler.removeCallbacks(mRunnable); // ... ... } |
或
1 2 3 4 5 | @Override public void onDestroy() { // If null, all callbacks and messages will be removed. mHandler.removeCallbacksAndMessages(null); } |