1.崩溃
Android崩溃分为Java和Native两种崩溃,一般处理思路如下:信息获取-问题定位-问题归类-方案确定-修改验证。
1.通过日志等相关技术获取相关信息:当前线程堆栈信息,主线程堆栈信息,版本信息,系统信息。
2.分析相关信息定位出问题发生场景,确认是Java还是Native崩溃,且定位出具体原因:OOM,空指针,ANR所致崩溃,或者其他原因,看能否复现相关场景。
3.如果是Navite崩溃,获取信号量,地址编码,通过Google 的Breakpad等相关工具,通过有效信息定位到具体崩溃点。
4.确定修改方案,修改bug,进行测试验证,发版。
崩溃的场景可能很多种,当时问题根源究其原因就是资源分配和资源调用出现了问题,有一些因为使用xspoed等多开技术,这些市面上的黑科技相关的场景也需要考虑。
上述崩溃很多问题是表象,其实根本原因是性能问题,比如OOM这个问题,可能需要我们去优化应用内存相关问题。
2.内存优化
内存在Android开发中占据中举足轻重的位置,内存直接影响到应用的性能甚至导致崩溃闪退。主要分为Java层和Native层两方面。
内存抖动:短时间内频繁创建回收对象所致。
内存泄露:短生命周期的对象被长生命周期对象引用,不能及时释放回收,占用内存。
内存溢出:系统分配给每个应用的内存有一个阈值,当应用占用的内存超过该值之后,就会出现内存溢出Out Of Memory【OOM】
对Java层的内存主要关注点是:图片引用加载,上下文Context,Handler,资源读写释放,内部类,线程等相关高频产生内存风险的技术点。
工具和策略:Memory Profiler,MAT,LeakCanary,TraceView等相关工具,灵活使用软引用和弱引用等相关技术。具体可以参照文章
Android内存优化
Native 这块需要针对C/C++ 层面去优化。
3.卡顿优化
卡顿优化一般是一个整体感受,简单来说资源吃紧,无论是CPU还是内存等相关资源,造成卡顿的原因有很多种,但是最终都会反映到CPU时间上。 CPU 时间分为两种:用户时间和系统时间。
- 用户时间就是执行用户态应用程序代码所消耗的时间;
- 系统时间就是执行内核态系统调用所消耗的时间,包括 I/O、锁、中断以及其他系统调用的时间。
优化的主要工具和策略:
TraceView:获取一段时间内所有函数调用的时间,再次去内部逐一分解。正因为是这样,存在trace文件的读写会导致部分数据不准确。
Systrace:主要用来监控系统耗时情况,开销很低。但不能支持程序代码相关分析,有一定局限性。
Android Studio 自带Profile 优化工具,查看火焰图等相关文件。
ANR:BlockCanary基于消息队列实现,检测主线程卡顿。
各种hook技术,对线程的监控。
4.启动优化
应用启动速度对用户来说是第一感官,直接影响用户下次是否使用该app。闪屏页,sdk初始化,首页布局过于复杂,网络等相关耗时操作都将会影响应用的启动速度。整体思路如下:具体启动时间获取--优化策略
- 时间获取:
- 冷启动和热启动对比,获取真正启动的时间
- 传统打点发获取启动时间
- 通过Systrace获取启动时CPU ,IO等相关资源的信息
- 通过TraceView获取相关方法调用的时间
- AOP方法获取启动时间
- 其他HOOK方法获取
- 策略
- 对闪屏页面增加过渡页
- 优化主页布局,刚进入时候需要迅速将页面展示,耗时等相关业务,可以延时。
- 对一些耗时的操作SDK初始化,网络请求,数据库读写等相关操作要做延迟处理或者异步加载,可以采用一些常用框架Alpha
- 采用IdealHandler做一些非紧急操作。
- 分包等技术,将非紧急业务移除主dex,这样主dex启动就会加快。
- 在ContentProvider的create方法中不要做耗时操作,因为其在application创建之前。
5.IO优化
IO读写是应用,CPU,磁盘三者交互的一个过程。一些常见的文件读写,数据库,网络等相关操作究其根本也就是IO操作。Android中常见的IO阻塞和相关解决策略如下:
- sharepreferences 读写会导致一定的阻塞和线程不安全。可以将commit改为apply进行数据保存。也可以用一些开源框架mmkv。采用mmap 通过映射的方式去读写数据
- 避免对线程造成的阻塞。
- 采用三级缓存相关,内存-磁盘-网络(数据库)
- 对IO的监控,可以自建AMS
IO操作是一个复杂的过程,但IO操作不是简单地文件读写,IO是系统对其资源的的分配,应用对其资源的调用和释放。最直观的影响就是IO出现问题,会导致ANR。做好IO监控,及时处理。
6.存储
Android存储一般是指数据的存储,又与上文的IO有一定关系。一般存储方式分为以下几种:
- 文件存储
- SharedPreferences 存储
- 数据库Sqlite存储。
- 一些常用的开源框架mmkv,orm等。
上述各种存储方式其最底层都是基于文件存储,这也符合linux是的文件概念。无论是何种文件存储最终都会有进程,线程之间的通信,数据读写效率。这边会产生很多变种socket,广播,intent,mmkv,orm等相关实现方式。
7.网络优化
在Android中网络的快与慢直接影响用户的体验,网络相关的优化却不多,对于一般工程师来说会用一些通用的网络请求的开源框架,优化相关的工作很少涉及到。抛开外部网络速度手机性能不说,一般对于应用开发工程师来说主要是基于以下几点:
- DNS优化,利于OkHttp可以设置默认的dns。
- 网络缓存,指定请求的过滤,添加相关缓存和过滤器。
- 弱网络的模拟和保护
- 链接的创建与管理,链接复用
- 数据请求的加密与压缩
以上主要是网络优化的一些常用手段,且这些一些开源框架都有做到,一般不需要过多的关注。除了治还应该有防的方案:
- 统一网络请求库
- 建立网络监控系统
- Native层去优化网络相关业务
Chromium是一个比较好的工程,无论是网络,内存,IO,数据库等相关都有值得学习和研究的地方。其中网络框架Cronet值得去研究。
8.电池
电池优化主要是集中于以下几点:
- 各种感应器sensor等相关资源获取用完记得释放,定位,重力等相关。
- PowerManager用完释放
- View 的layout 和ondraw 等方法中避免过多业务操作,有的可以考虑通过动画实现。
- 相关动画用完记得释放。
- 网络不好时频繁获取网络请求会加大电池的耗电
- 定时操作JobScheduler 和Alarm 以及一些定时相关的可以设置一些策略,使用WorkManager。
9.UI绘制
UI绘制是一个常见的技术优化点,层级较多复杂的UI往往会导致应用过度渲染,这样会影响应用的流程性。一般UI绘制这块会有几个优化点
治:
- 尽量使用include、viewstub、merage相关标签,减少不必要的绘制和增加布局的重用性
- 自定义View 在layout和onDraw方法中不要做过多的复杂逻辑处理,该方法过于耗时的话会导致UI卡顿。
- 布局可以考虑一些框架异步布局,这些已经有一些成熟的方案。
- 可以考虑开启一些硬件加速器相关。
防:
- 监控view页面的绘制和帧率。BlockCanary和Choreographer 的使用
- 适配不同尺寸的UI。
10 安装包优化
安装包的大小会影响app的下载转化率,对于用户来说消耗流量网络,对于开发者来说服务器带宽也有影响。同样功能的app,用户当然会选择包体小的应用。一般主要是有以下几种方式优化:
- 开启混淆和无有资源去除
- 图片等相关资源压缩,一些图片可以采用svg等相关技术替代,通过熊猫压缩。
- 第三方sdk无用功能剔除,so库压缩,特别是so这种非启动需要的库,可以考虑应用启动后下载,再进行加载。
- 积极使用第三方库AppBundle,AndResGuard 等相关技术。
- 分包,非紧急的业务采用插件化进行加载和处理。
其中打包资源这块可以采用一些hook技术进行极致压缩,但要注意信息保留,因为解决bug的同事也是需要这块信息,例如facebook的相关Redex技术
监控:
- 采用微信的AMS框架Matrix 进行监控,其本质是打包完成之后对apk进行检查,是否有进行上述相关处理,例如是否混淆,是否开启无用资源去除开关等。
- 对每次代码提交后进行编译的产物和上次编译出来的产物进行包体对比,如果包体增长超过一定限度,可以进行预警和提示,相关人员检查代码资源,决定是否进行合并。
网友评论