Android性能优化之异常处理&应用瘦身

简介

常见的异常无非就是ANR和OOM,掌握如何避免这两种异常有助于提升应用性能。另外,应用瘦身虽然不是性能的优化,而是app的优化,所以也放到这篇文章一起分享。

异常处理

ANR

原因

简述一下哪些地方是主线程:

  • Activity的所有生命周期回调
  • Service默认执行在主线程
  • BroadCastReceiver的onReceiver回调
  • 没有使用子线程的looper的handler的handlerMessage(),post(Runnable)方法
  • AsyncTask的回调,除了donInBackground方法,其他都是在主线程

ANR就是程序无响应异常(Application Not Responding)

在主线程中做了耗时操作,容易出现ANR

  • 一般的主线程对输入事件处理超过5S
  • 主线程在执行BroadCastReceiver的onReceiver()方法时,超过10S
  • 主线程在执行Service的各个生命周期函数时超过20S未处理完毕
  1. 耗时的网络访问
  2. 大量的数据读写
  3. 数据库操作
  4. 硬件操作(比如camera)
  5. 调用thread的join()方法、sleep()方法、wait()方法或者等待线程锁的时候
  6. service binder的数量达到上限
    7.service忙导致超时无响应
  7. 其他线程持有锁,导致主线程等待超时
  8. 其它线程终止或崩溃导致主线程一直等待。

方案

  1. 避免在主线程执行耗时操作,所有耗时操作应新开一个子线程完成,然后再在主线程更新UI。
  2. UI线程尽量只做跟UI相关的工作
  3. 耗时的工作(比如数据库操作,I/O,网络操作),采用单独的工作线程处理
  4. 使用Thread 或handlerThread时,可提高线程优先级,加快执行时间
  5. 使用AsyncTask 处理短时的操作,由于AsyncTask 是串行执行的,高频的操作会造成阻塞。如果操作很频繁的任务或耗时较长的任务交给HandlerThread,支持手动管理操作流。如果高度并行且量级较大的任务,可以交给ThreadPoolExecutor,可有自动的管理线程的创建销毁,根据任务负载平衡,调整线程优先级。

OOM

原因

OOM全称为“Out of memory”,即内存溢出异常.

  1. 内存溢出 当前占用的内存+申请的内存 > Dalvik虚拟机的最大内存限制
  2. 内存抖动 对象频繁的创建和回收,区别于内存溢出。
  3. 内存泄漏 内存由于各种原因未释放,无法被GC回收,导致的资源浪费。积累的多了会造成OOM

优化

  1. 【选择合适的图片尺寸进行加载】,需要缩略图时不加载大图,ListView在滑动时不进行加载
  2. 【及时释放Bitmap内存】Bitmap是通过BitmapFactory创建,并且具体是通JNI实现的,所以有一部分内存的在Java会自动被GC,但是在C里面的内存,只能通过调用recycle()来释放。
  3. 【图片压缩】加载图片之前先用inSampleSize(缩放比例)属性,计算出一个合适的缩放比例,避免不必要的大图加载。
  4. 【inBitmap属性】inBitmaps属性会提高安卓系统对Bitmap分配与释放的执行效率。通过这个属性Bitmap解码器去尝试使用已经存在的内存区域,新解码的bitmap不会先申请内存,而是尝试使用上一张bitmap占用的内存区域。(及时有很多图片,也只会占用屏幕能展示的一张图片的内存大小)
  5. 【捕获异常】系统在读取Bitmap的时候内存容易出现OOM异常,所以在实例化bitmap的时候要捕获异常处理。
  6. 【ListView复用ConvertView,LRU缓存】ListView中大量重复的条目,要对ConvertView复用。如果加载图片,可以使用LRU机制缓存图片(最近最少使用)
  7. 【避免在onDraw()创建对象】如果在onDraw()频繁创建对象会导致内存突然上升,频繁GC,内存抖动,严重了会OOM
  8. 【慎重使用多进程】使用多进程会使得代码逻辑更加复杂,如果使用不当,它可能会导致显著增加内存。

其他优化

线程优化

尽量使用线程池,避免在程序中存在大量的Thread。线程池可以重用内部的线程,从而避免了现场的创建和销毁所带来的性能开销,同时线程池还能有效地控制线程池的最大并发数,避免大量的线程因互相抢占系统资源从而导致阻塞现象发生。

Service使用优化

  1. 查看service是否存活以及降低优先级:
    假如一个service工作完成,但是来不及关掉或者kill掉,用户又看不见,所以这个service将会一直在后台运行,势必耗电。所以我们可以降低某些不常用service进程的优先级,在系统内存吃紧的情况下, 进程优先级低的service容易被系统kill掉。除此之外,可以利用监听系统广播来判断service状态是否存活,死亡即可手动kill掉。
  2. 用IntentService代替Service开发:
    普通服务一旦启动之后,就会一直处于运行状态,必须调用stopService()或者stopSelf()方法才能让服务停止下来。为了简单的创建一个异步的、会自动挺值得服务,Android专门提供了一个IntentService类。IntentService在运行完毕后自动停止,减少耗电量。

应用瘦身

  1. 只是用一套资源,例如只使用720P的一套资源
  2. 在gradle使用minifyEnabled进行Proguard混淆的配置,可大大减小APP大小
  3. 在gradle使用shrinkResources去除无用资源,并配合Android Studio自带的 “Remove Unused Resources”小插件。
  4. 使用svg矢量图替代png图标,占用资源更少
  5. 删除无用的语言包,在gradle中配置 resConfigs "zh"
  6. 使用图片压缩网站压缩png Tinypng的官方网站:http://tinypng.com/
  7. .so库文件能删除不必要的就尽量少保留.so库文件
  8. 使用7zip压缩打包工具,建议开启7zip,注意白名单的配置,否则会导致有些资源找不到
  9. 清理三方库和冗余代码
  10. 支持插件化,酌情选择

写在最后

  1. 很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

    领取方式:Android技术交流群653583088

猜你喜欢

转载自blog.csdn.net/qq_43257419/article/details/88721351