Android性能优化视频

1.android main Thread:System Events,Input Events,Application,Services ,Alarm,UI Drawing

16 milliseconds 将重绘一次屏幕或者1s60frams将会看起来平滑

dropped frame  当处理evnent时间过长将错过16ms的绘制时间,导致少绘一帧

AsyncTask helps get work on/off ui thread
HandlerThread 定义了thread callbacks
ThreadPool 处理大量并行任务
IntentService 在非UI线程处理intent

2.MessageQueue 可以填充intent ,Runnable ,msg 
HandlerThread来消费Queue内的东西
而其他的thread则可以产生这些东西
android 为每个程序创建一个进程,一个进程内维持一个HanlderThread,就是main Thread

3.View are not thread safe  
UI对象创建,使用和销毁都应该在主UI线程
如果在其他线程使用则会引起各种错误,在其他线程修改或者引用都会引起各种异常
仅仅是引用都可能出现错误:如果view从view树中移除,而后线程才完成那么引用将会出现问题
view默认引用着他的宿主 activity,所有当view泄露以后,那么activity也将泄露
 内部类隐式地引用着外部类,在acitivty内创建的asyntask就隐式地持有宿主acitivty实例,所以如果 asyntask如果完成不了,
则activity将一直在内存中不能释放

不要持有任何UI对象在非UI线程中

利用回调view对应的callback来实现UI的修改和更新则可以解决问题,然后判断callback是否存在。

4.默认情况下所有的asyncTask的耗时都执行在同一个线程,他们使用的是一个msg queue,有时候出现阻塞
所以可以使用AsyncTask.executeOnExecutor让耗时操作分别在不同的线程里执行

cancel aysncTask 在执行后台的时候设置检查是否被cancel的flag,当被取消的时候将结果设置为invalid
Doinbackground {
if(isCancelled)
{}
for(i
if(isCanceled()
{}
如果被取消掉,AsyncTask将调用canceled在ui Thread,而不是执行PostExecute

5.HandlerThread用于 no-UI,no-aysncTask thread来处理耗时的任务
aysncTask如果在后台处理一个较长时间的任务,而他的aysncTask将阻塞,他不太适合处理较长时间的任务,而且aysncTask将的pre和post都是在UI线程里执行

HandlerThread 的looper可以接受其他线程的msg,然后在该线程的hanler来处理,当需要更新UI的时候,调用runOnUIThread来更新UI
可以设置Priority来实现该thread优先处理

6.ThreadPoolExcutor来实现线程池的使用
可以使用Runtime.getRuntime.availableProcessors()活动的core,不能代表真实的物理核,可能其中一个在asleep
获取core来设定线程池的初始值和最大值

Renderscript可以用来处理large-scale图片

7.intentservice 继承自service 同时它拥有一个HandlerThread来处理intent onHandlerIntent

intentservice拥有一个intent queue,如果他处理较长时间的intent,那么可能会影响其他响应intent
intentsevice 是service,所以利用service的各种好处,比如获取context
intentsevice与ui 交互 runOnuiThread或者使用braodcastReceiver

intentservice可以使得app免得被system kill
app kill优先级  has 前台acitivty >no 前台activity +intentservice > no 前台activity 

8.当acitivity使用线程的时候,activity被销毁时候,但thread未完成,所以会有各种问题

loaders是在activity内的,和acitivty生命周期紧密相连,所以他会跟随activity的生命周期变化
loadermanager将是activity处理数据加载的最好选择

9.android 设置线程的优先级基于App的生命周期,处于前台app的线程占有90%-95%的cpu时间
可以通过android.os.Process.setThreadPriority来设置优先级
AysncTask和intentSerivce有自己的默认优先级,一般不需要修改
默认的时候,创建的线程都有相同的优先级,Default

11.在自己的设备上读取数据比从网络上快多了,所以要实现有用的数据缓存
利用http下载时候可以实现缓存,但默认的情况下http不能缓存
配置 HttpResponseCashe.install来设置http的缓存
用httpResponseCashe.getInstalled来获得缓存并flush
他可以利用到所有的基于http的网络连接
BitmapFactory.decodeStream(InputStream) new URL(pathToImage).getContent));
HttpClient client 

如果缓存满了,将自动删除未经使用的旧文件
服务器可以通过http 1.1设置缓存策略来实现对缓存的控制,来实现对无用文件的删除 Cashe-Control max-age = pulibc

DiskLruCashe可以帮助实现缓存

Volly okHttp 帮助实现网络各种情况缓存
Picasso帮助实现图像缓存管理

ARO Tool可查看网络

12.同步数据不要过度
网络是最大的耗电王,他不仅在处理时芯片耗电,而且在处理后的20-60S也会持续耗电
同步策略:分清楚那些马上发生的事和可以推迟发生的事的区别
最好关闭定期更新的服务器,用云服务器自动推送
可以采用退避策略:当没有数据同步的时候,同步延迟双倍的时间
也可以采用基于用户习惯的同步方式:比如跑步,睡觉或其他需求时同步;或者在Wifi状态或者充电状态时同步
GCMNetworkManager安排面向网络的服务:处理网络连接,指数退避等等

Networking Traffic Tool帮助检测网络

13.提前获取用户将要使用的网络请求可以节省网络和电池的消耗,
一般情况下一次性获取1-5mb data比较合理
未来1-2分钟将要使用的数据
可以根据不同的网络情况去获取 4G获取12张图标的时间=2G获取3张图片的时间
GCMNetworkManager安排面向网络的服务:处理网络连接,指数退避等等

14.根据不同的网络情况 ConnectivityManager来获取当前网络情况
可以自己计算大概网络请求的时间然后设定二个阀值
当高于阀值得时候 60ms 主动获取
介于中间的时候 主动提前获取
低于120ms时候  推迟获取
当然阀值可以根据用户的情况不同可以做相应的改变

15.冗余文件的传输消耗网络,消耗电量
造成冗余文件的两种方式:图像和序列化数据
图像     Alhpa  Lossy Qualit Size
PNG    yes                  great   bad
JPG                 yes      good    good
WEBP yes       yes      good    good
如果不适用alpha通道,那么就避免适用PNG照片,因为PNG不同被压缩

利用JPG 和 WEBP图片格式可以改变图片的质量来实现图片的大小改变 在图片的质量和尺寸之间做出权衡
缩略图因为很小,所以可以尝试改变图片的大小,放低图片的质量
可以在服务器存储不同分辨率和质量的图片,以匹配不同分辨率的情况

xml和json是很冗余的文件,它有很多空格符号等等冗余,仅仅是为了方便人们阅读
protocol Buffers  ; Nano-Proto-Buffers; FlatBuffers可以显著减少数据冗余

任何冗余压缩都是由Http协议栈进行GZIP压缩
应该采用结构阵列格式,将普通结构转化成数组结构

16.service从系统层面讲,服务需要消耗创建,调度运行甚至销毁来消耗系统时间和内存资源
service可能影响屏幕每16ms刷新一次时间,并丢失一帧
90%的情况尽量不要使用service 
利用线程工具都可以达到的效果,线程工具消耗更小的资源而且不需要占用UI线程

GCM
BroadcastReciever
LocalBroadcastReciever
WakefulBroadcastReciever
HadlerThread
AysncTaskLoaders
IntentServices 都可以用来实现service需要的功能而不必花费额外的资源

如果实在找不到替代servcie的方法,那么使用service,但尽量不要多花service一分钟时间
startService   必须调用stopService 或者stopslef才停止,如果不停止,service将停在那里等待,并且消耗资源
bindService 一直待着,直到所有的调用unbindService才停止或者程序结束

当调用startService 然后bindService 如果调用了unbindService ,service任然不会停止,直到调用stopService
最好不要将 service闲置

Systrace 可以帮查看系统时间去哪了,也可以查看程序有生命响应

17.多余的库的闲置代码会封装在app里 增大代码的编译大小,同时大的apk下载也是需要负担
同时Android 默认最多65K的方法限制

Proguard 不仅可以使得 类,方法,域编可以使用语义模糊来代替,使得加大代码的反编译程度
同时它可以把代码缩小
开启Proguard  gradle 设置Minfy enalbe = true

18.gradle 中设置 minifyeable =true shrinkResource = true 可以启用gradle扫描本地或库中没有用到的资源方法 
但是gradle不会丢弃多语言文件和不同尺寸layout文件夹

19.从RAM获取数据比从hard drive上获取数据更快捷
缓存:把频繁使用的数据存储起来,以后用到的时候可以方便快捷地使用

20.绝大多数代码中不需要100%的精确计算,所以可以根据实际情况做近似计算:比如 计算两个地方的距离

21.多度绘制:应用程序绘制在屏幕上的某个像素或视图之后又被重新绘制
解决过度绘制:剔除那些没必要的绘制代码,剔除掉所有遮盖对象和离屏对象
搜索数据库的时候也用到剔除方法

22.线程帮助做耗时工作

23.小的函数和方法反复调用会有大量的消耗,所以可以用批处理来解决它
批处理图像转换,
批处理网络请求:每次打开无线电的时候都有消耗,所以应该把1到2分钟的请求聚集起来,打开一次无线电,同时发送请求
自定义图:把每次小的矩阵的变化变为一次大的举证变换
数据库插叙批处理:把每次查询小的操作合并为一次查询

24.序列化就是取得数据并转换成格式化的数据块,在以后的时候又被转换回成内存对象

序列化:服务端,安卓设备之间传送数据包,两个进程之间传送数据,硬盘中存储用户偏好
Serailizable,ObjectOutputStream会占用大量内存和编码,整体运行缓慢

Gson转化有较高的效率,但是Gson必须使用json格式,json,xml这样的文本有大量的冗余

android 内部的xml资源文件会在打包时候特殊处理,所以无需担心文本冗余

编码解码工具:Nano-pro-buffers 针对Android开发的 buffers
FlatBuffers产生更小的数据,同时解码和编码时间也较少,几乎不存在消耗

有的情况压根不需要序列化:
用户偏好 SharedPreferencs
运行程序间传送:parcelable 打包
大量数据:SQLite

性能问题:了解警告并作出选择的过程
 
25.构造函数数组,类数组序列化有很多的冗余
在序列化的时候它的属性名称都是重复而多余
数组构造函数可以去掉冗余
http在进行传送的时候使用的Gzip来压缩,它是找重复的

26.当从服务器上拉取数据来更新UI的时候,在拉取数据的这一段时间内,可以使用旧的数据来显示UI
可以在本地利用Flatbuffers 或者sqlite来缓存数据,当然同时得告诉用户现在正在拉取新数据,不要留一个空白的页面给用户

27位了保存电量,android可以减少给cpu提供电压,这样cpu有更少的能量来执行代码,副作用是降低cpu执行速度
代码需要更长的时间来执行
电池是移动开发的全部 系统为了执行速度和消耗电量做了很好的协调

systrace

28 hashmap占用了大量的内存 ,通过hash去索引value,这样就要一个大的存储以防冲突,这样就有很多内存没有使用
arraymap和hashmap的功能相似 他有两个存储,一个存储key的散列,一个顺序存储key-value 所以有更小的内存花费
它也可以通过索引来迭代
arraymap使用场景:存储对象小于1000,访问多,但删除插入少
                              当map包含map的时候,而对子map又经常进行迭代

29.基本类型为了能在泛型容器中使用,所以提供了包装类 Integer
Integer total =0 for(i=0;i<100;i++){total +=i} 创建了大量的Integer对象
每次在基本类型的map添加取出的时候都会装箱和拆箱会创建大量的对象
为了避免这种情况android提供了对应的map  SparseBoolmap SparseIntmap SparseLongmap 

Allocation Tracker
TraceView

30.hashmap存储时候必须使用对象作为key,int就会被装箱为Integer

31.当应用被载入的时候,系统会给应用一定的内存,它会将所有应用的DEX载入这个空间,这个内存的其他堆空间
不要使用Enum它比正常的int花费多20字节,会增大DEX体积,从而占用空间

32.onTrimMemory当系统资源不够的时候回调,来让app释放自己不必要的资源,它提供不同的int值
在application fragement activity service contentprovider都有回调
isLowRamDevice用来检测是否在低内存设备运行,返回true的时候表明内存小于等于512兆

33.Android垃圾回收机制只能回收内存中不被任何物体引用的对象
流失是指一个对象不再被需要了,它还是在系统某处被引用,根链条上的泄露使得整个都不能被回收
view包含了创建activity的引用,activity引用了大量内存对象和其他内存项目
当view流失时,它所引用的所有的activity和其他资源都会流失
如果屏幕旋转,会创造新的一个activity
避免view流失应该排在内存管理的首位

不要引用asyncTask callback 异步回调函数中的view ,因为callback可能在某个时候在会执行,而此时可能activity早就
销毁 可能造成流失或者引用为null
不要在静态对象中引用view ,静态对象和你的app的process拥有同样的生命周期
不要将view放进没有明确内存模型的集合中

34.位置信息 setInterval设置间隔 保持精度和电量的平衡
                   setPriority来实现优先级设置

GPS耗电但精度高  网络精度差但耗电小  
主动提供位置:当别的App获取位置的时候会把位置推送过来
FusedLoactionProvider 可以简化位置推送

battery historian可以监控电量使用

35.Relativelayout先根据子视图的位置和大小,然后根据子视图计算好的位置和大小来重置位置和大小,然后算出合适的位置
然后对边界做出相应的调整
两次布局:一次确定大小,一次确定边界
每当RelativeLayout里面有一个元素改变,就会发生重新布局

measurewithLargestChild的线性布局也将发生两次布局

避免:努力最小化视图层级,在完全没必要的情况下避免调用requestLayout

36.无线网络是电池的头号杀手,传输的数据越多用户的成本越大
优化性能:减少无线电活跃时间;减少获取的数据的大小

绝对不能定期轮询服务器更新数据,浪费带宽和电量,借助云推送是一个好的选择
云推送不可用的情况下可以使用,降低轮询频率非常重要,采用补偿模式,每次间隔时间*2
或者使用批处理来优化单一的网络请求,降低电池的损耗
或者使用预处理来节省未来执行的时间
GCMNetworkManager可以帮助使用网络

37.批处理将请求联合处理的方式,你只需为一次唤醒付出成本
截断请求,将请求放在一个队列里面,等待以后再执行

38.无线电芯片并不是一直活跃消耗能量的,它起始于一个节电状态,当需要传输数据时,它会开启并传输数据,一旦数据发送完成时,无线射频芯片会保持唤醒一段时间,防止服务器有回应,如果一段时间依旧没有活动,无线电会返回到休眠状态来保存电池寿命

wakeup Hardware ---packet send ---packet receive --keep awake
保持唤醒有一个电量消耗,发送和接受数据电量会达到峰值

优化在于  WHEN和HOW
批处理移除了唤醒和等待的成本
JobScheduler api可以用来处理批处理
预加载 你可以预测未来5-10分钟可能需要的东西,提前获取内容
确保下载和上传的东西高度压缩,cpu压缩的成本远远低于无线电传输数据的成本

Networking prifiling

42.短时间配置大量的临时对象,为内存施加巨大的压力,同时不断的触发垃圾回收
使用对象池来解决,典型的内存抖动是因为创造了大量的临时对象,比如位图,图片他们被创建存留一段时间后被回收
导致污染并分割内存堆,本质上对象池是将对象引用到一个可用对象的列表上,可以重新使用而不需要重新创建一个新的对象
只有对象池为空的时候才重新创建新的对象
不要在每次需要的时候配置一个对象,而是一次配置大量的对象,应该在应用加载的时候向对象池中填入新对象,这样在第一次使用对象的时候可以达到最快
注意清理对象池,否则会发生内存流失

43.迭代器在迭代元素的时候,要额外配置,而且要避免在迭代的时候对象被修改
所以在移动开发中避免适用迭代器使得带来性能问题。使用for循环index迭代是最快的,其次是简单for 再次是迭代器

Trust But verify

44.当内存不够的时候,你需要释放掉已经使用的内存才能加载新的对象

可以一次从硬盘中加载多个对象缓存起来,以待将来使用

LRU 用来处理缓存,当有新对象加入的使用,如果内存不够会删掉以前的
占用大小设置  ActivityManager am = getSystemService(Context.ACTIIVTY_SERVICE)
                      int    avaleMemoryBytes = am.getMemoryClass() 1024*1024
LruCache lru = new LruCache( avaleMemoryBytes/8)\

45.LINT

51.一旦图片离开磁盘进入内存,那些很好的压缩保存方式消失了

在利用JPEG和PNG之前先要被载入内存被解码成系统可以渲染的格式,一旦被载入它们不再是它们压缩的格式了,一直待在CPU的内存中

默认的情况下图片被载入为位图时,它们被处理称为32byte每像素 红色,绿色,蓝色透明通道各8比特,即使加载不带透明通道的图片,比如
JPEG图片也是如此,目前android不支持24比特的图片格式,即使加载不带透明通道的也会被转换成为32比特的格式,这些图片被屏幕渲染之前,首先
被作为纹理传送到GPU,这样你每创造一张位图同时要占用CPU内存和GPU内存

android支持的图像格式  ARGB_8888   每像素占位  32
                                      RGB_565                       16
                                     ARGB_4444                      16
                                       ALPHA_8                         8
他们可提供更小的CPU和GPU覆盖区,减少内存堆碎片提高性能,但同时视觉质量会下降

RGB_565 没有Alpha通道,可在小屏幕上使用
ARGB_4444 有Alpha通道,但像素质量变小,但可以在头像或者小的图片使用

Android不支持灰度模式位图,Alpha_8比较长用于Alhpa通道蒙板

可以先用Alpha_8创建一个简单的灰度头像,然后用颜色渲染,将其转换成屏幕实际的颜色,虽然渲染要一定的花费,但从内存使用上会好很多

默认情况下PNG,JPEG和WebP格式不支持较小的文件格式,所以需要设置inPreferredConfig为任何你想要的文件格式,系统在load完图片以后,
会帮你转换成你想要的格式,但这需要额外的时间  时间和空间的转化

52.PNG是 android图像内容的主要部分,但PNG膨胀率高

PNG是一种简单的文件格式,它对像素数据进行的是无损耗压缩算法,图像完全等同于原始图像
JPEG应用有损耗压缩算法,可以比PNG有更高的压缩率

清除PNG膨胀问题,应用有损压缩算法 Script PNG 提供大量的不同压缩,可以提供正确显示质量的压缩率

如果不需要使用透明度,那么你根本不需要使用PNG格式,仔细调整压缩率的JPEG图片更适合
可以考虑单独使用Alpha_8的图片存储透明度的JPEG图片,然后和JPEG图片重新组合成图片,这样比JPEG的RGB有更好的效果

WebP图像格式,它支持透明度处理和有损和无损压缩,也支持动画,在4.2以上的系统支持

这些只是帮你在服务器传送到客户端的时候有用,而不是CPU使用时候

53.当内存里的图片的大小大于屏幕显示的大小的时候,高分辨率图片会带来大量的性能问题

所以改变原始图片的大小,缩放位图
CreatSaledBitmap 在现有的一张图片上依据提供的标准生成一张新的bitmap,但需要现有的一张位图,花费太大

需要加载的时候就设置大小的方法 inSamleSize,每隔in读入一个像素 
inScale ,inDesity,inTargetDesity 先利用inScale减少像素,将图片生成接近大小的图片,然后使用Desity过滤图片
inJustDecodeBounds设置知道图片的大小

Glide,Picasso库可以实现使用这些方法

54.Bitmap代表大块的连续内存,大量的头像,缩率图创建会触发垃圾回收机制,造成内存抖动

当像用户提供大量的图片时,图像加载时会触发大量的垃圾回收事件,位图拓展对象池解决这个问题

对象池,当你处理完某个对象时,你将其加入一个可用对象的列表,而不进行释放,下一次需要相同类型对象时
可以将池中对象从新目的化

Android在加载位图的时候默认创建一个新的位图,你可以将载入位图指向一个已经存在的内存片,而不是创建新的位图
BitmapOptions的inBitmap设置,重新使用已经存在的bitmap

滑动显示图片的时候,你只需配置可显示的位图的值,然后重复使用配置好的位图

Size,夸像素格式

Glide库

58.Android系统会每16ms对你的活动重新绘制,16ms内运行完所有的逻辑来更新屏幕,从而达到60帧每秒的效果
如果错过了这个时间,就会发生丢帧的现象,系统会尝试绘制新的一帧,但它还没准备好,所以什么都刷不出来
用户在32ms看到是同一帧画面,这就是所谓的丢帧情况,用户所说的延迟和卡顿

错过原因:过多时间进行视图某些部分的绘制,绘制太多的重叠对象,一次运行大量的动画

Hierarchy Viewer 查看活动的视图层级
Profile GPU Rendering 
Show GPU Overdraw
GPU View updates
TraceView检测底层到底什么原因导致丢帧

59.过渡绘制:一帧内某个像素在屏幕上被重新绘制了很多次
为了提供性能应该把overdraw减少到最少次

开发者模式-GPU重复绘制
没有overdraw 本色-一次蓝色----2次绿色-----三次粉色------四次红色

移除不必要的背景可以减少overdraw

60.刷新频率:Refresh Rate 屏幕每秒内更新显示的次数,以HZ表示,经常取决于硬件

帧频:Frame Rate GPU每秒内可以绘制的帧数 fps ,帧数越高越好

GPU获取你的数据进行绘制,然后硬件会将其输出转到屏幕上,在绘制的时候这样动作反复发生

假如帧率比刷新频率快,会出现图像撕裂:当刷新频率和帧率不相同的情况

图像卡使用了内存的一部分来绘制这个帧,每一个新的帧会覆盖在前面一帧,从顶端开始每次输出一行数据,当屏幕刷新的时候,它不知道
从哪里开始,它可能有当前帧的一半和前一帧的一半,解决这个问题关键是双缓存技术

当把GPU的一帧绘制到内存后,叫后台缓存 backBuffer,它会将其复制到内存副区域,叫做帧缓存区 FrameBuffer,当它绘制第二帧时,它会
完成后台缓冲,而帧缓冲区不收影响,当屏幕刷新的时候,它从帧缓冲区进行刷新 VSYNC 或者叫做垂直同步:避免了屏幕刷新的时候,把
数据从后台缓冲区复制到帧缓冲区

当GPU刷新速度高于屏幕刷新速度是理想的,GPU会垂直同步等待下一次屏幕的刷新,这时候帧频会根据屏幕刷新频率进行捕捉

当屏幕刷新率大于GPU绘制速度,会出现卡顿,延迟,打结

一定要保证帧频,保证GPU能迅速获取它需要的数据,并且有时间在下次刷新前进行绘制

61.开发者模式--Profile GPU Rendering - on Sreen as bar
每一个垂直的栏目代表一帧的渲染,越高代表渲染时间越长 绿色代表了16ms一帧的线,为了达到60帧每秒,必须保证每一条垂直的线在16毫秒
线以下,当超过时候就会出现卡顿

蓝色的代表在Java花了多长时间来更新显示列表,在视图被渲染之前,它必须转换成适合GPU的格式,蓝色条记录的完成两步所需要的时间
当蓝色条边长,可能一大堆视图无效了,或者自定义view在onDraw里面做了复杂的逻辑

红色条代表了Android的2D渲染显示列表需要的时间,Android通过和OpenGL_ES协调来绘制显示列表,将列表传送给GPU ,然后绘制在屏幕
越复杂的view越需要多的时间来绘制,当红色条升高,表示view比较复杂

橘色代表了处理时间,CPU等待GPU的信息,来感知它接受到的指令,这条越长,代表GPU处理大量的工作,绘制大量的复杂视图,需要很多的
OpenGL渲染指令来完成绘制

62.大脑会持续地处理你的眼睛传送可视图像
至少10-12帧每秒的速度相信图片动是一个动作
24帧每秒是人眼会感觉出来的流畅画面,以前很多电影就是24帧
60帧每秒是最好的效果,大部分人接受不了更高的帧数
人眼对非连续变化感知是非常高,比如忽然从60到20,人会感知到不流畅性

保持在60帧,保持速度不变
16ms每帧的动作 1000ms/60 frames = 16.666 ms/frame 
16ms完成每帧的工作,比如网络,输入,计算和渲染,每一帧都保持流畅

63.通过光栅化将xml等转换成像素
将button textview等转换成纹理像素显示在屏幕上
光栅化非常耗时

GPU 专为加速光栅化而设计,GPU本身设计的为了绘图有各种绘图基元
CPU主要是为了GPU屏幕绘制之前,将这些基元送至GPU,在android上通过OpenGL来实现

基元----CPU ----OpenGL --------GPU ------光栅化-----屏幕

绘制的时候,首先CPU要将控件转换成像素和纹理 基元  然后送至GPU光栅化

要减少对象转换成基元时间,和基元传到GPU时间,OpenGL_ES容许你上传内容到GPU,然后留在那里,将来你想绘制一个按钮的时候,只需要参照之前
存在于GPU中的网格,告诉OpenGL怎么绘制就可以了。优化光栅化性能意味着将尽可能多的数据存入GPU,越快越好,最好不要动他,就是Android的性能机制

尽可能优化光栅化性能:手机提供的主题资源,也就是位图和可绘制的图像集合成为一个单独的纹理,并长传到GPU,同时上传的还有常用多边形网格
这样每当需要绘制这些的时候,都不需要唤醒并转化格式,这些已经在GPU里面了,所以显示出来也十分迅速

显示图像意味着存储设备中的图像到CPU,然后将他们送至GPU进行绘制
绘制文字时候在CPU需要把字形光栅化成纹理,然后上传到GPU,每一行每一个字都是如此,所以很复杂
动画则需要每一帧都上传到GPU绘制
Android不会将整个应用的每一帧都重新绘制,只会绘制屏幕范围内修改过的内容

为了性能,动画需要在16ms内完成每一帧的GPU资源更新和最后的光栅化

64.Android在绘制图案时,都需要将高级的XML对象转换成GPU可以接受的文件,然后进行屏幕渲染,这要借助一个内部对象,叫显示列表
显示列表包含了所有GPU渲染需要的东西

在首次渲染图案的时候,会生成一个列表,通过提交绘图命令至GPU来执行显示列表,如果将来想再次渲染这个视图的时候,只需再次执行显示列表
如果视图的某些部分改变,之前显示的视图列表不再有效,需要重新生成显示列表,重新绘制在屏幕上
每次视图内容改变的时候,它会重复显示列表的生成过程,在屏幕上继续执行

当视图大小改变时,衡量阶段会开始,他会浏览整个视图,要求每个视图提供新的大小,如果改变了视图位置,导致重新布局,它会穿过布局,计算
出每个视图应该放置的位置
要提高系统整体渲染的性能,布局失效最小化是个不错开始

Profile GPU Rendering
GPU View updates
Hierarchy Viewer

65.移动应用最容易掉进去的陷阱是多次绘制项目

过度绘制的原因是硬件使用太多的周期来绘制屏幕上的像素,而这些像素最终都不能组成图片,例如Nav Drawer的滑动出来的,需要绘制他下面所有的
项目,但它最终却不会显示在屏幕上
Android系统完全隐藏不透明下面的子项目 但在自定义视图的时候可以通过canvas.cliprect()容许你为自己给出的视图规定绘制边界,只有矩形框内的项目可以被绘制,其他的都被忽略,在自定义视图中设置哪些可以被绘制,哪些忽略

ClipRect可以帮助CPU和GPU的性能,ClipRect之外的不会被CPU提交给硬件,也就不会产生额外的负担,但在ClipRect交汇的地方会被绘制,从而避免GPU
为以外的地方着色

canvas.quickreject 检测出clipRect的交叉部分,在clipRect之外跳出绘制过程

67.硬件消耗电量来执行任务叫做超时电流消耗

待机模式时几乎不消耗电量  一旦使用或唤醒屏幕时,电量消耗会上升 ,当工作完成后,设备会主动进行休眠,休眠可以保存电池电量

蜂窝无线网络也是消耗电量非常多的,每当设备准备发送数据的时候,为了让设备准备投入使用,会出现一个唤醒耗电高峰,接下来会一个耗电高峰来发送数据
接受数据也要消耗大量电量,完成执行工作后,硬件在一小段时间内保持开启,以防止短时间内有新的数据需要接受

Battery Historian


68.唤醒已经休眠的手机,是Android上不必要消耗电量的最大元凶

69.内存泄露,你为大量对象配置了内存,但不释放这些内存,时间久了这些对象会变成大块固定的内存块,迫使应用只能使用剩余的堆内存,
如果你在短时间内配置并释放大量对象,也会出现内存不足的问题,使得堆被大量临时对象所填充,会启动垃圾回收器

Memory monitor 下降,代表垃圾回收器触发,当短时间有大量的下降代表出现了大问题

当躲开了垃圾收集活动,就会有更多的帧时间做其他的事

70.ART内存分配 Zygote Space +Non moving space +Image Space +Main Alloc Space +Large obj Sapce

GC 任何控制代码遭遇线程后都会停止,垃圾回收器会运行,直到完成时,才会继续执行代码

大量配置对象,一旦达到内存保留的阀值,垃圾回收器就会整理空间,这会耽误你帧处理时间,用户会体验到性能的问题

大量的GC触发可能是内存流失 
确保不要在for循环里配置新对象 ,可以考虑使用对象池来实现,当然也需要自己手动释放对象

Allocation Tracker

71.内存泄露:配置的内存没有被释放

GC:找到程序以后不会用到的数据对象,重新回收这些对象占用的资源

Dalvik(

Android会决定将对象配置在哪个区块,每个区块都有指定单位大小,随着对象配置的增加,所占用的区块的区域增加
这时GC会触发,释放空间以为将来的配置使用

不同版本的GC表现不同
Dalvik 垃圾回收机制是世界终结者,任何运行的代码都会停止,直到垃圾回收活动结束
一点GC运行的时间过长,或者频繁触发GC ,那么就会有性能问题

ART 倾向于移除大的GC停顿,但还是在垃圾回收结束后会有一个小的暂停

72.内存泄露时候,内存不够,GC会不断的启动来回收,

检查活动: 先给检查的acitivty做一个内存快照,然后配置一个空的activity,要检查的acitivty转换空的activity ,然后启动GC,如果清理得当,
任何配置信息都讲会被清除,如果第二个堆有任何可疑数据,那么就是泄露

73.Memory Monitor
普通的GC事件并不影响性能,但GC被频繁的触发就会占用帧时间,引起性能问题

你可能感兴趣的:(Android)