1. android流畅度评估及卡顿优化
Google定义:界面呈现是指从应用生成帧并将其显示在屏幕上的动作。要确保用户能够流畅地与应用互动,应用呈现每帧的时间不应超过16ms,以达到每秒60帧的呈现速度(为什么是60fps?)。
如果应用存在界面呈现缓慢的问题,系统会不得不跳过一些帧,这会导致用户感觉应用不流畅,我们将这种情况称为卡顿。
来源于: Google Android的为什么是60fps?
16ms意味着1000/60hz,相当于60fps。这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。12fps大概类似手动快速翻动书籍的帧率, 这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。 24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用支出。 但是低于30fps是 无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,超过60fps就没有必要了。如果我们的应用没有在16ms内完成屏幕刷新的全部逻辑操作,就会发生卡顿。
首先要了解Android显示1帧图像,所经历的完整过程。
如图所示,屏幕显示1帧图像需要经历5个步骤:
常见的丢帧情况: 渲染期间可能出现的情况,渲染大于16ms和小于16ms的情况:
上图中应该绘制 4 帧数据 , 但是实际上只绘制了 3 帧 , 实际帧率少了一帧
判断APP是否出现卡顿,我们从通用应用和游戏两个纬度的代表公司标准来看,即Google的Android vitals性能指标和地球第一游戏大厂腾讯的PrefDog性能指标。
以Google Vitals的卡顿描述为准,即呈现速度缓慢和帧冻结两个维度判断:
PerfDog Jank计算方法:
帧率FPS高并不能反映流畅或不卡顿。比如:FPS为50帧,前200ms渲染一帧,后800ms渲染49帧,虽然帧率50,但依然觉得非常卡顿。同时帧率FPS低,并不代表卡顿,比如无卡顿时均匀FPS为15帧。所以平均帧率FPS与卡顿无任何直接关系)
当了解卡顿的标准以及渲染原理之后,可以得出结论,只有丢帧情况才能准确判断是否卡顿。
mpsys 是一种在设备上运行并转储需要关注的系统服务状态信息的 Android 工具。通过向 mpsys 传递 gfxinfo 命令,可以提供 logcat 格式的输出,其中包含与录制阶段发生的动画帧相关的性能信息。
借助 Android 6.0(API 级别 23),该命令可将在整个进程生命周期中收集的帧数据的聚合分析输出到 logcat。例如:
这些总体统计信息可以得到期间的FPS、Jank比例、各类渲染异常数量统计。
命令 adb shell mpsys gfxinfo <PACKAGE_NAME> framestats 可提供最近120个帧中,渲染各阶段带有纳秒时间戳的帧时间信息。
关键参数说明:
通过gfxinfo输出的帧信息,通过定时reset和打印帧信息,可以得到FPS(帧数/打印间隔时间)、丢帧比例((janky_frames / total_frames_rendered)*100 %)、是否有帧冻结(帧耗时>700ms)。
根据第2部分的通用应用卡顿标准,可以通过丢帧比例和帧冻结数量,准确判断当前场景是否卡顿。并且通过定时截图,还可以根据截图定位卡顿的具体场景。
如上图所示,利用gfxinfo开发的检查卡顿的小工具,图中参数和卡顿说明如下:
根据上面对gfxinfo的帧信息解析,可以准确计算出每一帧的耗时。从而可以开发出满足腾讯PerfDog中关于普通卡顿和严重卡顿的判断。
依赖定时截图,即可准确定位卡顿场景。如下图所示(此处以PerfDog截图示例):
通过第3部分的卡顿评估方法,我们可以定位到卡顿场景,但是如何定位到具体卡顿原因呢。
首先了解卡顿问题定位工具,然后再了解常见的卡顿原因,即可通过复现卡顿场景的同时,用工具去定位具体卡顿问题。
重点就是,充分利用gfxinfo输出的帧信息,对卡顿问题进行分类。
了解了高效定位卡顿的方法和卡顿问题定位工具,再熟悉一下常见的卡顿原因,可以更熟练的定位和优化卡顿。
SurfaceFlinger 负责 Surface 的合成,一旦 SurfaceFlinger 主线程调用超时,就会产生掉帧。
SurfaceFlinger 主线程耗时会也会导致 hwc service 和 crtc 不能及时完成,也会阻塞应用的 binder 调用,如 dequeueBuffer、queueBuffer 等。
后台进程活动太多,会导致系统非常繁忙,cpu io memory 等资源都会被占用,这时候很容易出现卡顿问题,这也是系统这边经常会碰到的问题。
mpsys cpuinfo 可以查看一段时间内 cpu 的使用情况:
当线程为 Runnable 状态的时候,调度器如果迟迟不能对齐进行调度,那么就会产生长时间的 Runnable 线程状态,导致错过 Vsync 而产生流畅性问题。
system_server 的 AMS 锁和 WMS 锁 , 在系统异常的情况下 , 会变得非常严重 , 如下图所示 , 许多系统的关键任务都被阻塞 , 等待锁的释放 , 这时候如果有 App 发来的 Binder 请求带锁 , 那么也会进入等待状态 , 这时候 App 就会产生性能问题 ; 如果此时做 Window 动画 , 那么 system_server 的这些锁也会导致窗口动画卡顿。
Android P 修改了 Layer 的计算方法 , 把这部分放到了 SurfaceFlinger 主线程去执行, 如果后台 Layer 过多,就会导致 SurfaceFlinger 在执行 rebuildLayerStacks 的时候耗时 , 导致 SurfaceFlinger 主线程执行时间过长。
主线程执行 Input Animation Measure Layout Draw decodeBitmap 等操作超时都会导致卡顿 。
Activity resume 的时候, 与 AMS 通信要持有 AMS 锁, 这时候如果碰到后台比较繁忙的时候, 等锁操作就会比较耗时, 导致部分场景因为这个卡顿, 比如多任务手势操作。
应用里面涉及到 WebView 的时候, 如果页面比较复杂, WebView 的性能就会比较差, 从而造成卡顿。
如果屏幕帧率和系统的 fps 不相符 , 那么有可能会导致画面不是那么顺畅. 比如使用 90 Hz 的屏幕搭配 60 fps 的动画。
由上面的分析可知对象分配、垃圾回收(GC)、线程调度以及Binder调用 是Android系统中常见的卡顿原因,因此卡顿优化主要以下几种方法,更多的要结合具体的应用来进行:
在计算机和通信领域,帧是一个包括“帧同步串行”的数字数据传输单元或数字数据包。
在视频领域,电影、电视、数字视频等可视为随时间连续变换的许多张画面,其中帧是指每一张画面。
2. androidUI卡顿原理分析及Vsync信号机制
一、UI卡顿定义
1、用户角度:app操作界面刷新缓慢,响应不及时;界面滑动不够流畅;
2、系统角度:屏幕刷新帧率不稳定,掉帧严重,无法保证每秒60帧,导致屏幕画面撕裂;
二、UI卡顿常见原因分析以及处理方案
1、过度绘制:
原因:界面布局设计不合理或者过于复杂导致系统无法在16毫秒内完成渲染,view过度绘制导致CPU或者GPU负载过重,View频繁触发measure、layout操作,导致measure、layout累计耗时严重以及整个View错误的频繁重新渲染;
方案:优化界面布局,使界面布局视图扁平化,去除不必要的背景颜色,减少透明色的使用;
方案依据原理:尽量减少View在系统中measure、layout、draw的累计时间;
2、UI线程的复杂运算
原因:UI主线程运算耗时
方案:减少UI线程中数据运算,使用子线程处理耗时任务
3、频繁GC
原因:(1)、内存抖动;(2)、瞬间产生大量对象,消耗内存;
方案:尽量避免在循环逻辑或者onDraw方法中频繁创建新对象和使用局部变量;
三、android Vsync机制
1、什么是Vsync ?
Vsync 是Vertical Synchronization(垂直同步)的缩写,是一种在PC上很早就广泛使用的技术,可以简单的把它认为是一种定时中断。而在Android 4.1(JB)中已经开始引入VSync机制,用来同步渲染,让AppUI和SurfaceFlinger可以按硬件产生的VSync节奏进行工作。
2、Android屏幕刷新过程
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,屏幕的刷新过程是每一行从左到右(行刷新,水平刷新,Horizontal Scanning),从上到下(屏幕刷新,垂直刷新,Vertical Scanning)。当整个屏幕刷新完毕,即一个垂直刷新周期完成,会有短暂的空白期,此时发出 VSync 信号。所以,VSync 中的 V 指的是垂直刷新中的垂直-Vertical。
3、没有使用Vsync的情况
可见vsync信号没有提醒CPU/GPU工作的情况下,在第一个16ms之内,一切正常。然而在第二个16ms之内,几乎是在时间段的最后CPU才计算出了数据,交给了Graphics Driver,导致GPU也是在第二段的末尾时间才进行了绘制,整个动作延后到了第三段内。从而影响了下一个画面的绘制。这时会出现Jank(闪烁,可以理解为卡顿或者停顿)。这时候CPU和GPU可能被其他操作占用了,这就是卡顿出现的原因;
4、使用Vsync同步
CPU/GPU接收vsync信号,Vsync每16ms一次,那么在每次发出Vsync命令时,CPU都会进行刷新的操作。也就是在每个16ms的第一时间,CPU就会响应Vsync的命令,来进行数据刷新的动作。CPU和GPU的刷新时间,和Display的FPS是一致的。因为只有到发出Vsync命令的时候,CPU和GPU才会进行刷新或显示的动作。CPU/GPU接收vsync信号提前准备下一帧要显示的内容,所以能够及时准备好每一帧的数据,保证画面的流畅;
5、多级缓冲
Android除了使用Vsync机制,还使用了多级缓冲的策略来优化屏幕显示,如双重缓冲(A + B),当Display buffer A 数据时,CPU/GPU就已经在buffer B 中处理下一帧要显示的数据了。
可是,当系统资源紧张性能降低时,导致GPU在处理某帧数据时太耗时,在Vsync信号到来时,buffer B的数据还没准备好,此时不得不显示buffer A的数据,这样导致后面CPU/GPU没有新的buffer准备数据,空白时间无事可做,后面Jank频出
因此采用三级缓冲来解决系统对性能不稳定导致的卡顿
当出现上面所述情况后,新增一个buffer C 可以减少CPU和GPU在Vsync同步间的空白间隙,此时CPU/GPU能够利用buffer C 继续工作,后面buffer A 和 buffer B 依次处理下一帧数据。这样仅是产生了一个Jank,可以忽略不计,以后的流程就顺畅了。
注:在多数正常情况下还是使用二级缓冲机制,三级缓冲只是在需要的时候才使用;
3. 知识体系四:Android动画工作原理
1.Android 动画的工作原理?
在android系统中动画分为两种分别是帧动画和属性动画。对于动画的工作原理主要涉及到的是帧动画的实现。
帧动画主要有旋转RotatleAnimation,缩放ScaleAnimation,透明AlphaAnimation,平移TranslateAnimation等都是Animation的子类。Animation控制动画的效果,Transformation 对动画进行计算。
对于动画的原理简单说就是从一个动画的启动状态,到动画结束状态,和动画持续总时间,在这段时间中任一时间点动画的状态计算和显示的过程。
计算 :是通过Animation的getTransformation()方法首先对时间进行归一化时间让时间在0~1之间,进行计算。满足条件之后就会调用applyTransformation()方法处理实现动画类型的计算。当前时间点的转换状态保存到Transformation 的Matrix中等待显示的时候使用。
显示 :动画显示工作主要依赖于Choreograther类,此类是线程唯一的,Choreograther和Handler用法类似,都是通过post一个Runnable对象到队列中等待VSYSC屏幕垂直同步信号刷新(16ms)刷新一次,然后触发ViewRootImpl的view的遍历工作,回调到view.draw()方法时就会把之前applyTransformation 计算的此时刻的Transformation 的Matrix赋值到Canvas上, 这也就是为什么我们使用帧动画时候我们的view的属性并没有改变,这就是根源因为计算得到的Matrix被Canvas使用了,并没有直接赋值到我们的view上。 对于属性动画来说主要使用animator实现看下面解析:
2.Animation 和 Animator 的区别?
Animation和Animator都是抽象类,都有子类,Animation通过Transformation对动画进行Matrix转换来作用到Canvas上实现动画效果。而Animator只是一个工具类,主要是用来控制在一段时间内某一个值的变化过程,然后我们再根据这个值来作用到view的属性上,以此来实现动画效果。为了让这个变化的过程能达到加速减速等变化效果系统提供了插值器Interpolator。他们的实现思想都是一致的。
3.帧动画 和 属性动画的区别?
4. Android 绘制与 16ms 不得不说的故事
刷新率:每秒屏幕刷新次数。
帧率:GPU 在一秒内绘制的帧数。
虽然现在有的厂商推出了高刷新率的手机,但是主流的还是 60Hz,即1秒显示60帧,1000ms / 60 frames ≈ 16.67 ms/frames,为了保证 App 的流畅度,我们应该尽量让每帧的绘制时间不超过 16ms。
Android 的显示过程可以简单概括为:应用程序把经过 measure(测量)、layout(布局)、draw(绘制)后的 surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显示屏幕上,通过 Android 的刷新机制来刷新数据。换言之,应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层通过刷新机制把数据更新到屏幕上。
以下是有关概念的解释:
在 Android 中每个 view 都会经过 measure 和 layout 来确定其所在的大小和位置,然后绘制到 surface (缓冲区上),绘制是由 ViewRootImpl 类中 performTraversals() 方法发起的。
Android支持两种绘制方式: 和 。硬件极速从 Android 3.0 开始支持,它在 UI 显示和绘制效率方面远高于软件绘制,但是它的也有缺点:
经过多次绘制后,要显示的 view 相关的数据存储(如大小和位置)在 Surface 的缓冲区中,接下来渲染操作交由系统进程中的 SurfaceFlinger 服务来完成,这是一个 IPC(进程间通信)过程。SurfaceFlinger 的主要工作流程如下:
当 Android 应用层在图形缓冲区中绘制好 View 层次结后,应用层通过 Binder 机制与 SurfaceFlinger 通信并借助一块匿名共享内存把图形缓冲区交给 SurfaceFlinger 服务。由于单纯的匿名共享服务在传递多个窗口数据时缺乏有效的管理,所以匿名共享内存就被抽象为一个更上层的数据结构——SharedClient,在 SharedClient 中,最多有 31 个 SharedBufferStack,每个 SharedBufferStack 都对应一个 Surface 即一个 Window。 这表明一个 Android 应用程序最多可以包含 31 个 window 。
绘制的过程首先是 CPU 准备数据(measure、layout等),GPU 负责栅格化、渲染。因为图像 API 不允许 CPU 直接与 GPU 通信,所以要通过一个图形驱动的中间层来进行连接。图形驱动里面维护了一个队列,CPU 把 display list(待显示的数据列表)添加到队列中,GPU 从这个队列中取出数据进行绘制,最终在屏幕上显示出来,如下图所示:
Android 系统每隔 16ms 会发出 VSYNC 信号,触发对 UI 进行渲染,如果每次都渲染成功,就能够达到流畅画面所需的 60PS。
双缓冲顾名思义是有两个缓冲区(上文提到的 SharedBufferStack),分别是 FontBuffer(又叫作 FrameBuffer) 和 BackBuffer。UI 总是先在 Back Buffer 中绘制,然后再和 Font Buffer 交换,渲染到显示设备中,即只有当另一个 buffer 的数据准备好后,才会通过系统调用来通知显示设备切换 Buffer。
双缓冲机制在大部分情况下是适用的,但是如果某个环节出现了问题,CPU 资源就有可能存在浪费,如下图所示:
VSYNC 类似与时钟中断。竖线分割的部分代表 16ms 的时间段。正常情况下,在每一时间段内,Display 显示一帧数据(即每秒60帧)。
上图中在第二个 16ms 时间段内,Display 本应显示 B 帧,但是因为 GPU 还在处理 B 帧,导致 A 帧被重复显示。与此同时,在第二个时间段内,处于 CPU 处于空闲状态,造成了浪费。因为 A Buffer 被 Diaplay 在使用(SufaceFlinger 用完后不会释放当前的 Buffer,只会释放旧的 Buffer),B Buffer 被 GPU 在使用,这就是 双缓冲机制的局限性。
Android 4.1 版本中对 Android Display 系统进行了重构,引入了三个核心元素:
在第二个 16ms 时间内,CPU 使用 C Buffer 绘图,虽然还是会多显示 A 帧一次,但是后续的显示相对双缓冲机制就顺滑多了。但是 Buffer 并不是越多越好,从上图可知,在第二个时间内,CPU 绘制的第 C 帧数据要到第四个 16ms 才能显示,这比双 Buffer 多了 16ms 的延迟。由此可见,双缓冲保证低时延,三缓冲保证稳定性。
整个流程简单来说就是 CPU/GPU 会接收到 VSYNC 信号,触发对 UI 进行渲染(每 16ms 显示一帧)。 在 16ms 内需要完成两项任务:将 UI 对象转换为一系列多边形和纹理(栅格化)和 CPU 传递处理数据到 GPU ,更详细的内容可以看这篇文章 Android的16ms和垂直同步以及三重缓存 。
了解 Android 绘制流程后,我们不难反推 Android 应用程序卡顿的原因:
5. Android UI卡顿原因及解决办法
渲染机制介绍
为了分析UI卡顿,我们有必要理解一下渲染机制,这套渲染机制适用于绝大部分的屏幕渲染,其中包括Android手机等众多屏幕设备。
渲染的一些重要参数:
屏幕刷新理想的频率(硬件的角度):60Hz
理想的一秒内绘制的帧数,帧率(屏幕刷新的角度):60fps
这两个参数都是理想值,指代的都是同一个概念。实际情况中难免会比它们低。在60fps内,系统会得到发送的VSYNC(垂直刷新/绘制)信号去进行渲染,就会正常地绘制出我们需要的图形界面。Android手机进行绘制的时候,GPU帮助我们将UI组件等计算成纹理Texture和三维图形Polygons,同时会使用OpenGL---会将纹理和Polygons缓存在GPU内存里面。
其中,VSYNC:有两个概念
Refresh Rate:屏幕在一秒时间内刷新屏幕的次数----有硬件的参数决定,比如60HZ,即屏幕每秒刷新60次
Frame Rate:GPU在一秒内绘制操作的帧数,比如:60fps,
基本结论
要达到60fps,就要求:每一帧只能停留16ms。(大概就是1000ms/60 ~= 16ms刷新一次)
内存抖动是因为大量的对象被创建又在短时间内马上被释放。
瞬间产生大量的对象会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,也会触发GC。即使每次分配的对象占用了很少的内存,但是他们叠加在一起会增加Heap的压力,从而触发更多其他类型的GC。这个操作有可能会影响到帧率,并使得用户感知到性能问题。
Android里面是一个三级Generation的内存模型,最近分配的对象会存放在Young Generation区域,当这个对象在这个区域停留的时间达到一定程度,它会被移动到Old Generation,最后到Permanent Generation区域。
Android每个16ms就会绘制一次Activity,通过上述的结论我们知道,如果由于一些原因导致了我们的逻辑、CPU耗时、GPU耗时大于16ms( 应用卡顿的根源就在于16ms内不能完成绘制渲染合成过程,16ms需要完成视图树的所有测量、布局、绘制渲染及合成 ),UI就无法完成一次绘制,那么就会造成卡顿。
比如说,在16ms内,发生了频繁的GC:
在第一个16ms内,UI正常地完成了绘制,那么屏幕不会卡顿。
在第二个16ms内,由于某些原因触发了频发的GC,UI无法在16ms内完成绘制,就会卡顿。
UI卡顿外部和内部常见原因
下面总结一些常见的UI卡顿原因:
1.内存抖动的问题
2.方法太耗时了(CPU占用)
1) CPU计算时间,CPU的测量、布局时间
2)CPU将计算好的Polygons和Texture传递到GPU的时候也需要时间。OpenGL ES API允许数据上传到GPU后可以对数据进行保存,缓存到display list。因此,我们平移等操作一个view是几乎不怎么耗时的 。
3) GPU进行格栅化
当我们的布局是用的FrameLayout的时候,我们可以把它改成merge,可以避免自己的帧布局和系统的ContentFrameLayout帧布局重叠造成重复计算(measure和layout)。
使用ViewStub:当加载的时候才会占用。不加载的时候就是隐藏的,仅仅占用位置。
CPU优化建议
针对CPU的优化,从减轻加工View对象成Polygons和Texture来下手:
View Hierarchy中包涵了太多的没有用的view,这些view根本就不会显示在屏幕上面,一旦触发测量和布局操作,就会拖累应用的性能表现。那么我们就需要利用工具进行分析。
如何找出里面没用的view呢?或者减少不必要的view嵌套。
我们利用工具:Hierarchy Viewer进行检测,优化思想是:查看自己的布局,层次是否很深以及渲染比较耗时,然后想办法能否减少层级以及优化每一个View的渲染时间。
我们打开APP,然后打开Android Device Monitor,然后切换到Hierarchy Viewer面板。除了看层次结构之外,还可以看到一些耗时的信息:
三个圆点分别代表:测量、布局、绘制三个阶段的性能表现。
1)绿色:渲染的管道阶段,这个视图的渲染速度快于至少一半的其他的视图。
2)黄色:渲染速度比较慢的50%。
3)红色:渲染速度非常慢。
GPU优化建议就是一句话:尽量避免过度绘制(overdraw)
一、背景经常容易造成过度绘制。
手机开发者选项里面找到工具:Debug GPU overdraw,其中,不同颜色代表了绘制了几次:
6. 针对Android的性能优化集中哪些方面
一、概要:
本文主要以Android的渲染机制、UI优化、多线程的处理、缓存处理、电量优化以及代码规范等几方面来简述Android的性能优化
二、渲染机制的优化:
大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。
*关于JobScheler的更多知识可以参考http://hukai.me/android-training-course-in-chinese/background-jobs/scheling/index.html
七、代码规范
1)for loop中不要声明临时变量,不到万不得已不要在里面写try catch。
2)明白垃圾回收机制,避免频繁GC,内存泄漏,OOM(有机会专门说)
3)合理使用数据类型,StringBuilder代替String,少用枚举enum,少用父类声明(List,Map)
4)如果你有频繁的new线程,那最好通过线程池去execute它们,减少线程创建开销。
5)你要知道单例的好处,并正确的使用它。
6)多用常量,少用显式的"action_key",并维护一个常量类,别重复声明这些常量。
7)如果可以,至少要弄懂设计模式中的策略模式,组合模式,装饰模式,工厂模式,观察者模式,这些能帮助你合理的解耦,即使需求频繁变更,你也不用害怕牵一发而动全身。需求变更不可怕,可怕的是没有在写代码之前做合理的设计。
8)View中设置缓存属性.setDrawingCache为true.
9)cursor的使用。不过要注意管理好cursor,不要每次打开关闭cursor.因为打开关闭Cursor非常耗时。Cursor.require用于刷cursor.
10)采用SurfaceView在子线程刷新UI,避免手势的处理和绘制在同一UI线程(普通View都这样做)
11)采用JNI,将耗时间的处理放到c/c++层来处理
12)有些能用文件操作的,尽量采用文件操作,文件操作的速度比数据库的操作要快10倍左右
13)懒加载和缓存机制。访问网络的耗时操作启动一个新线程来做,而不要再UI线程来做
14)如果方法用不到成员变量,可以把方法申明为static,性能会提高到15%到20%
15)避免使用getter/setter存取field,可以把field申明为public,直接访问
16)私有内部类要访问外部类的field或方法时,其成员变量不要用private,因为在编译时会生成setter/getter,影响性能。可以把外部类的field或方法声明为包访问权限
17)合理利用浮点数,浮点数比整型慢两倍
18)针对ListView的性能优化,ListView的背景色与cacheColorHint设置相同颜色,可以提高滑动时的渲染性能。ListView中getView是性能是关键,这里要尽可能的优化。
getView方法中要重用view;getView方法中不能做复杂的逻辑计算,特别是数据库操作,否则会严重影响滑动时的性能
19)不用new关键词创建类的实例,用new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。
clone()方法不会调用任何类构造函数。在使用设计模式(Design Pattern)的场合,如果用Factory模式创建对象,则改用clone()方法创建新的对象实例非常简单。例如,下面是Factory模式的一个典型实现:
20)public static Credit getNewCredit() {
return new Credit();
}
改进后的代码使用clone()方法,如下所示:
private static Credit BaseCredit = new Credit();
public static Credit getNewCredit() {
return (Credit) BaseCredit.clone();
}
上面的思路对于数组处理同样很有用。
21)乘法和除法
考虑下面的代码:
for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }
用移位操作替代乘法操作可以极大地提高性能。下面是修改后的代码:
for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }
22)ViewPager同时缓存page数最好为最小值3,如果过多,那么第一次显示时,ViewPager所初始化的pager就会很多,这样pager累积渲染耗时就会增多,看起来就卡。
23)每个pager应该只在显示时才加载网络或数据库(UserVisibleHint=true),最好不要预加载数据,以免造成浪费
24)提高下载速度:要控制好同时下载的最大任务数,同时给InputStream再包一层缓冲流会更快(如BufferedInputStream)
25)提供加载速度:让服务端提供不同分辨率的图片才是最好的解决方案。还有合理使用内存缓存,使用开源的框架
引用:Android性能优化的浅谈
7. 如何测量Android应用的帧率FPS
通过 [设置]->[开发者选项]->[GPU呈现模式分析] ->[在屏幕上显示为条形图] 进行直观的取样,截图如下:
绘制过程中的不同颜色具有不同的含义,详细解释请移步>> 官网查看更多。
那么是不是说我只需要打开界面去数一下超过绿色阈值的柱状图有多少就可以观察我们应用的流畅度了?然而并没有,因为这个方式获取到的渲染时间只是UI主线程上的绘制行为,目前我所接手的项目,采用的方式是捕捉相机的数据然后放到GPU中去进行绘制,有单独的绘制线程,单独的视图,所以这个方案并不适合我手上的项目。