Android开发技术周报183学习记录

Android开发技术周报183学习记录

教程

Android性能优化来龙去脉总结

记录

一、性能问题常见

内存泄漏、频繁GC、耗电问题、OOM问题。

二、导致性能问题的原因

1.人为在ui线程中做了轻微的耗时操作,导致ui线程卡顿。
2.layout过于复杂,无法在16ms完成渲染。
使用RelativeLayout替换LinearLayout,说是可以减少布局层次,然而,现在不再建议使用RelativeLayout,因为ConstraintLayout才是一个更高性能的消灭布局层级的神器。ConstraintLayout基于Cassowary算法,而Cassowary算法的优势是在于解决线性方程时有极高的效率,事实证明,显性方程组是非常适合用于定义用户界面元素的参数。
3.同一时间执行的动画过多,导致CPU或者GPU负载过重。
主要是因为动画一般会频繁变更view的属性,导致display失效,而需要重新创建一个新的displayList,如果动画过多,这个开销可想而知。
4.view过度绘制的问题。
可以通过手机设置里面的开发者选项,打开Show GPU Overdraw的选项,发现问题,尽量往蓝色靠近。
5.gc过多。
6.资源加载导致执行缓慢。
两种解决办法:a.预加载,即还没有来到路径之前,就提前加载好。
b.要等到用到的时候加载,加一个进度条。
7.工作线程优先级设置不对,导致和ui线程抢占cpu时间。
使用Rxjava时需要注意,设置任务的执行线程可能会对性能产生较大的影响。
8.静态变量

三、解决

1.GPU过度绘制,定位过度绘制区域
直接在开发者选项,打开Show GPU Overdraw,就可以看到哪块需要优化。
减少布局层级,使用ConstraintLayout替换传统的布局方式。
检查是否有多余的背景色设置。
2.主线程耗时操作排查
开始strictmode,止痒以来,主线程的好事操作都将以警告的形式呈现到logcat当中。
直接怀疑的对象加@DebugLog,查看方法执行耗时。DebugLog注解需要引入插件hugo,这个是Android之神JakeWharton的早期作品,对于监控函数执行时间非常方便,直接在函数上加入注解就可以实现,但是有一个缺点,就是JakeWharton发布的最后一个版本没有支持release版本用空方法替代监控代码。
3.对于measure,layout耗时过多的问题
一般这类问题是由于布局过于复杂的原因导致,建议使用ConstraintLayout减少布局层级,问题一般得以解决,如果发现还存在性能问题,可以使用traceView观察方法耗时,来定位下具体原因。
4.leakcany
用于内存泄漏检测,引入

dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}

注意引入方式中releaseImplementation保证在发布包中移除监控代码,否则,他自身不停的catch内存快照,本身也影响性能。
5.onDraw里面写代码需要注意
onDra由于大概每16s都会被执行一次,因此本身就相当于一个forloop,如果你在里面new对象的话,不知不觉中就满足了短时间内大量对象创建并释放,于是频繁GC就发生了,于是卡了。正确的做法是将对象放在外面new出来。
6.json反序列化问题
json反序列化是指将json字符串转变为对象,如果数据量比较多,特别是有相当多的string的时候,解析起来不仅耗时,而且还很吃内存。解决方法:
a.精简字段,与后台协商,相关接口剔除不必要的字段。保证最小可用原则。
b.使用流解析,使用Gson.fromJson即可,可以提高25%的解析效率。
7.viewStub&merge的使用
对于只有在某些条件下才展示出来的组件,建议使用viewStub包裹起来,include某布局如果其更不惧和引入他的夫布局一致,建议使用merge包裹起来。
8.加载优化
将耗时的操作封装到异步中去。
9.刷新优化
a.对于列表中的item的操作,有写只需要布局刷新,不应该让整个列表刷新。
b.对于较为复杂的页面,建议不要写在一个activity中,建议使用几个fragment进行组装,这样一来,module的变更可以只刷新某一个具体的fragment,而不用这个整个页面都走刷新逻辑。
10.动画优化
使用硬件加速来做优化,注意在动画做完之后,关闭硬件加速,因为开启硬件加速本身就是一种消耗。
11.耗电优化
a.建议在定位精度要求不高的情况下,使用wifi或英东网络定位,没有必要开启GPS定位。
b.建议先验证网络的可用性,在发送网络请求,比如,当用户处于2G状态下,而此时的操作是查看你一张大图,下载下来可能都200多k甚至更大,就没有必要去发送这个请求,让用户一直等待加载吧。

四、代码建议

(正确使用alarm,正确申请和释放wakelock)、(节制地使用service)、(当界面不可见时释放内存)、(Allocate Memery,Pd->model,使用优化过的数据集合)、(谨慎使用抽象编程)、(Try/Catch语句,应把其放在最外层)、(System.arraycopy()代替For循环复制)、(Hashmap->sparsearray)、(列表滚动停止之后加载网络图片)、(注意使用wrap_content)、(使用Canvas.cliprect()来帮助系统识别那些可见的区域,自定义view优化)、(对于定时任务尽量使用alarmmanager,而不是sleep或者timer进行管理)。
建议只用SpaseArray代替HashMap,因为SparseArray比HashMap更省内存,在某些条件下性能更好,主要是因为它避免了对key的自动装箱,它内部则是通过两个数组来进行数据存储的,一个存储key,另一个存储value,为了优化性能,它内部对数据还采取了压缩的方式来表示稀疏数据的数据,从而节省内存空间。
不到不得已,不要使用wrap_content,推荐使用match_parent,或者固定尺寸,配合gravity=’center’,因为在测量过程中,match_parent和固定宽度对应EXACTLY,而wrap_content对应AT_MOST,这两者对比AT_MOST耗时较多。

深入理解flutter的编译原理与优化

记录

查了一下flutter,不建议学习,不看了。

技术之外

GitHub 的用法与礼仪
记录

游客
Watch(关注):表示你对这个仓库中发生的事件感兴趣。
Star(星标):表示特别标记这个仓库。
Fork(分支):两种用途,一种是你要参与它,为它提交代码;另一种是觉得这个仓库可能会被原作者删除,因此Fork出来一份,这样即使作者删除了,也有一个Fork那个时间点的版本的快照。
贡献者
贡献的形式有两种:提issue和提pill request,这两者有一些共同的要求,包括:

  • 认真看病遵循对方给出的issue模板/PR模板。
  • 及时跟进,当对方有回复时应该尽早给出足够明确的回答。如果觉得对方的答复已经解决了你的问题,或者这个确实不是问题,就及时关闭,不要等作者动手。
  • 大多数仓库都要用英文提,但专门面向中文用户的仓库是例外。

提issue也就是提问题,可以再细分为两种:提BUG和提需求(Feature Request/Proposal)。
提BUG的基本要求是确认它是问题并把问题说清楚。
提需求的基本要求是要能坦然接受别人的拒绝。
提Pull Request(简称PR)也就是申请往主库中合并代码。提PR的前提是先Fork对方的仓库,而不要clone下来然后上传到自己的仓库,那样的话GitHub无法知道这俩库是同源的。
Fork之后,你的个人仓库中就有了一个分支仓库,可以往这个分支仓库中提交代码,觉得达到了PR的预定目标之后,就推送它,并回到GitHub页面中发起PR。
作者
作为仓库的作者,首先要在仓库中包含一个明确的LICENSE文件。
通常代码类的仓库会选择MIT等比较开放的协议,如果是开源*者,也可以选择GPL等比较激进的协议,但是要注意原则上GitHub不允许开放仓库中的代码使用私有/纯商业授权协议。
文档类的仓库通常会选择CC或者CC-BY-NC协议,两者的区别是前者允许商用,后者不允许商用或商用时需单独授权。

上一篇:20145222《信息安全系统设计基础》Linux常用命令汇总


下一篇:Greenplum 源码安装教程 —— 以 CentOS 平台为例