Android性能优化

启动优化

冷启动

冷启动指的是应用程序从头开始:系统的进程没有,直到此开始,创建了应用程序的进程。 在应用程序自设备启动以来第一次启动或系统杀死应用程序等情况下会发生冷启动。

Click Event ->IPC ->Process.start ->ActivityThread ->bindApplication ->LifeCycle ->ViewRootImpl

热启动

应用驻留在内存中,会从后台放回到前台展示,避免重复对象初始化、UI布局和渲染。

后台->前台

温启动

用户退出了应用,但随后又重启,这时候会进程和Activity生命周期都会重走。

LifeCycle

可使用一下工具获取启动时间:

  • TraceView
    wall time:方法执行总时间
    cpu time:cpu在这个方法上使用的时间

  • adb命令:adb shell am start -W –n /
    加上 -s 就是杀掉重启应用
    如果只关心某个应用自身启动耗时,参考TotalTime;
    如果关心系统启动应用耗时,参考WaitTime;
    如果关心应用有界面Activity启动耗时,参考ThisTime。

优化小技巧:

  • Theme主题切换:感觉上快了。在app启动时候使用一个带logo的主题,MainActivity起来后,在super.onCreate(savedInstanceState)前把主题setTheme回来。
  • 异步优化:使用封装的线程池,子线程(每个子线程只干一件事)分担主线程任务,并行减少时间。
    注意事项:
    1.不符合异步要求,要改;
    2.需要在某阶段完成,使用CountDownLatch保证线程同步;
    3.区分CPU密集型和IO密集型任务。CPU密集型则不能创建过多线程,会消耗CPU运算资源,而IO密集型则可以创建多个线程去操作。
  • 启动器优化
    1.区分主线程、子线程运用,非必主线程运行的都可以移植到子线程去做;
    2.执行时机、顺序依赖;
    3.使用IdleHandler优化;主要用在我们希望能够在当前线程消息队列空闲时做些事情。譬如 UI 线程在显示完成后,如果线程空闲我们就可以提前准备其他内容的情况下,不过最好不要做耗时操作。

内存优化

工具:

  • Memory Profiler
  • Memory Analyzer

内存抖动观察:内存使用图会程锯齿状,忽高忽低。

  • 使用Memory Profiler初步排查
  • 找循环或者频繁调用的地方

内存泄漏:可用内存减少,频繁GC。
内存溢出:OOM、程序异常退出。

获取Bitmap占用内存:

  • getByteCount
  • 一像素占用内存

图片优化:图片加载要控制宽高,压缩编码。

可使用hook方法去监听内存实时使用情况:

  • ARTHook:无侵入性、通用性强、兼容问题大,开源方案不能带到线上环境。
  • Epic:是一个虚拟机层面、以Java Method为粒度的运行时Hook框架。

优化方案:

  • 开启LargeHeap属性,有机会获取2倍的系统分配内存。注意:作为程序员的我们应该努力减少内存的使用,尽量想回收和复用的方法,而不是想方设法增大内存。当内存很大的时候,每次gc的时间也会长一些,性能会下降的。
  • onTrimMemory,这个方法执行,证明系统内存不足,必须要做资源释放,以保存app为上策,避免被系统杀死。
  • 使用SparseArray等。
  • 谨慎使用SharedPreference,读取的时候会加载全部数据到内存中,性能差。
  • 谨慎使用外部库,要清楚外部库写法,是否本身就存在内存泄漏等问题。

布局优化

一个像数最好只被绘制一次。可在开发者选项里面,开启调试GPU过度绘制,可以看到页面绘制情况。

优化方法:

  • 16ms内刷新不卡顿,刷新频率60Hz,在这个范围内可认为是流畅不卡顿的。
  • InflaterLayout.Factory:当我们使用自定义view时,需要在xml中使用完整类名,系统实际就是根据完整类名进行反射构建。我们可以自己new出view避免系统反射调用,提高效率。
  • AsyncLayoutInflater:WorkThread加载布局,回调主线程。加载布局xml文件是一个IO操作过程。
  • X2C:框架,APT编译器翻译XML为Java代码,解决IO读取、反射使用等问题。但不支持merge标签和使用系统Style。
  • 减少View树层级,尽量使用ConstraintLayout、不嵌套使用RelativeLayout、不在嵌套LinearLayout中使用weight。
  • 使用merge标签,共用父布局,但只能绘制在根view中。
  • 使用Viewstub,高效占位符,延迟初始化。
  • 去掉多余背景色,减少复杂shape使用。
  • 自定义view重叠时候要使用clipRect指定绘制区域,onDraw中避免创建大对象、耗时操作。

卡顿优化

工具:CPU Profilder、Systrace、StrictMode。

自动化卡顿检测方案原理:

  • 消息处理机制,一个线程只有一个Looper。
  • mLogging对象在每个message处理前后被调用。
  • 主线程发生卡顿,是在dispatchMessage执行耗时操作。

具体检测卡顿做法:

  • Looper在其loop方法中的死循环中有个mLogging对象,在执行的时候打印了一个Dispatching to日志,执行完成的时候有打印了一个Finished to日志。
  • 可以自定义Printer对象,让Handler的日志都通过我们自定义的Printer进行打印,然后收集日志信息,匹配Dispatching to和Finished to字段,如果在设定的某个时间内只有Dispatching to字段而没有Finished to字段,那么就说明发生了卡顿。发生卡顿后我们就收集此时的调用栈信息。

ANR介绍

会发生ANR的情况:

  • 按键5s。
  • 广播,前台10s,后台60s。
  • 服务,前台20s,后台200s。

检测方案:

  • Android Performance Monitor(BlockCanary):监控msg,如果应用发生卡顿,一定是在dispatchMessage中执行了耗时操作。通过给主线程的Looper设置一个Printer,打点统计dispatchMessage方法执行的时间,如果超出阀值,表示发生卡顿,则dump出各种信息,提供开发者分析性能瓶颈。
  • ANR-WatchDog库原理:开始线程->post改变数值->sleep一段时间->检测数值是否被修改->没有修改,证明发生ANR。
  • Lancet:轻量级AOP库,可使用它进行方法执行时间检测。

线程优化

线程使用情况:

  • 任意时刻,只有一个线程占用CPU,处于运行状态。
  • 多线程并发:轮流获取CPU使用权。
  • JVM负责线程调度:按照特定机制分配CPU使用权。

Android线程调度:

  • 设置线程nice值:在process中定义,值越小,优先级越高,默认是0,在Android中,nice的取值范围为-20~19。
  • cgroup,更严格的群组调度策略,保证前台线程获取更多的CPU。

Android异步方式:

  • Thread(直接new不易复用,频繁创建开销大)
  • HandlerThread(串行执行,不断从队列中获取任务)
  • IntentService(不占用主线程,优先级高,完成就结束)
  • AsyncTask(线程池,无需处理线程切换)
  • 线程池(易复用、定时、任务队列、并发数控制)
  • RxJava

注意事项:

  • 不要直接new Thread,不易复用。
  • 线程要有对应的名字,出问题时候容易定位。
  • 线程池要提取公共类,避免重复创建占用资源。
  • 线程注意设置优先级,合理利用资源。
  • IO密集型任务不消耗CPU,可以创建大的核心池。
  • CPU密集型则需要少于CPU核心数,对CPU占用较大。

网络优化

工具:

  • Network Profiler
  • 抓包工具(Charles,Fiddler,Wireshark,TcpDump)
  • TrafficStats
  • NetworkStatsManager

技巧:

  • 数据缓存,设置过期时间,避免重新获取。
  • 加上版本判断,只获取有变化的数据。
  • 数据压缩,GZip压缩。
  • 图片压缩,缩略图展示,使用webP格式。
  • 合并请求,减少次数。
  • DNS优化(阿里云)。
  • 协议版本升级。
    http/0.9版本:1991年,原型版本,功能简陋,只有一个命令GET,只支持纯文本内容,该版本已过时。
    http/1.0版本: 1996年5月,支持cache, MIME, method等。
    http/1.1版本: 1997年1月,默认建立持久连接,并能很好地配合代理服务器工作。还支持以管道方式在同时发送多个请求,以便降低线路负载,提高传输速度。
    http/2 版本: 2015年5月作为互联网标准正式发布,头部信息和数据体都是二进制,引入头信息压缩机制等。

电量优化

工具:

  • BatteryManager
  • Battery Historian
  • PowerManager.WakeLock

方案:

  • 特别注意视频播放。
  • 传感器使用。
  • 线程使用(AOP Run方法)。
  • 定位(考虑网络定位代替GPS)等。
  • 使用JobScheduler。

apk瘦身优化

可以在Android Studio里面Build中选择Analyze APK,看到apk包内各个资源大小。

方案:

  • 代码混淆(Proguard、AndResGuard资源混淆)。
  • 第三方库删减从简处理。
  • 避免使用枚举,枚举不仅仅会造成性能的问题,还会占用大量的内存。
  • 删除无用代码使用。
  • 删除无用资源文件,图片压缩或使用webp格式。
  • so移除,abiFilters设置指定so架构,代码加载对应so库。

列表页卡顿优化

  • 布局优化(减少层级,异步inflate)。
  • 图片压缩(大小、分辨率、编码格式)优化,滑动时候取消加载。
  • 使用viewHolder、convertView复用。
  • 耗时任务异步处理。
  • 注意字符串拼接,使用StringBuilder。

存储优化

  • 异步IO。
  • sp存储性能差,可用腾讯的MMKV代替。
    MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。

WebView优化

  • VasSonic:腾讯开源的、解决webview首屏提速的框架。
  • WebView在Application中提前初始化,复用。
  • WebView缓存。
  • 资源文件本地存储。

你可能感兴趣的:(Android性能优化)