High Performance之android高性能之路
2016-04-04 11:29
561 查看
背景:
此乃阅读实践High Performance一书的内容.硬件性能及电池续航
电池杀手之一:唤醒工具Wakelocks
Wakelocks可以唤醒(保持唤醒状态)移动设备的部分组件。电池杀手之二:唤醒工具Alarm
Alarm允许开发者设置时间执行特定的操作,特别是App在后台运行或者是设备处于休眠状态的时候。有时间精确性要求的提醒应该设置一个准确的Alarm(例如,创建一个闹钟App)。其他的情况可以使用不精确的Alarm,操作系统会自动协调合并Alarm来节省电量。下面的代码会每天在alarmTime(操作系统自动协调Alarm的时候,但是不确定是24小时的什么时候)的时候唤醒一次设备:
alarmManager.ssetInexactRepeating(AlarmManager.RTC_WAKEUP,alarmTime, AlarmManager.INTERVAL_DAY, alarmIntent);
Doze框架
Marshmallow添加了该框架来限制设备频繁的被唤醒。该框架有这么几个状态:
ACTIVE:Screen is on
INACTIVE:Screen is off, but device is awake
IDLE_PENDING:“Nodding off ” into Doze
IDLE:Device is asleep
IDLE_MAINTENANCE:A short window for all queued alarms and updates to occur
在屏幕关掉后,从INACTIVE到IDLE_PENDING至少需要30分钟,而进入到IDLE还需要30分钟,一旦进入IDLE,设备将会推迟所有的alarms直到maintenance窗口期到来,而每个窗口期IDLE_MAINTENANCE之间的延迟时间会不停的递增,最大为6h.
alarm和wakeLock唤醒操作都被延迟到IDLE_MAINTENANCE执行。
大杀器battery-historian
如何安装
过程有些多,请参考: https://github.com/google/battery-historian配置
收集跟踪数据之前,最好重置一下数据,为了收集尽可能多的数据,你可以开启报告全部wakelock的功能(这个功能只支持Lollipop及以上的系统):adb shell dumpsys batterystats --reset //报告全部wakelock的功能 adb shell dumpsys batterystats --enable full-wake-history //下载所有从手机上次全充满电之后的数据 adb shell dumpsys batterystats --charged
如果不开启–enable full-wake-history,则会显示
导出日志
adb bugreport > bugreport.txt
启动battery-historian
cd $GOPATH/src/github.com/google/battery-historian go run cmd/battery-historian/battery-historian.go [--port <default:9999>]
打开浏览器
输入 http://localhost:9999在显示的网页中载入 刚才的bugreport.txt文件即可。
JobScheduler(作业调度器)
Lollipop(5.0)之前:每个App中的wakelock和alarm都是相互独立的,所以当众多APP去唤醒的时候,做到同步唤醒是一个几率巧合事件,那么设备可能会被频繁的唤醒。
之后:
JobScheduler可以替代wakelock和alarm运行App的任务。可以看做是“互相协作的wakelock/alarm”API。设置唤醒时间范围,而不是准确的唤醒时间,那么可以这样理解,以前是自己开一辆空车上班,现在是大家拼车上班,这样就节省耗油。
//kJobId allows me to run multiple JobScheduler runs at the same time <snip> JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent); String delay = mDelayEditText.getText().toString(); //read delay time(s) from UI if (delay != null && !TextUtils.isEmpty(delay)) { builder.setMinimumLatency(Long.valueOf(delay) * 1000); } String deadline = mDeadlineEditText.getText().toString(); //Read deadline time from UI if (deadline != null && !TextUtils.isEmpty(deadline)) { builder.setOverrideDeadline(Long.valueOf(deadline) * 1000); } boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked(); boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked(); if (requiresUnmetered) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); } else if (requiresAnyConnectivity) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); } builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked()); //checkbox to force JS only when idle builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked()); //checkbox to force JS only when charging mTestService.scheduleJob(builder.build());
JobScheduler的另一个很炫酷的特点就是执行重复工作,并且可以指定执行的周期是线性还是指数衰减。如果你的App不处在前台,你可能不需要持续这种频繁的更新,因此,你可以让它们降低更新频率。当App重新打开的时候,用户仍然可以看到最新的数据,后台数据使用量却减少了。
JobScheduler有两种延时工作的衰减方式:线性(慢衰减)或指数(快衰减)
UI渲染性能
研究显示,0-100ms的延迟会让用户感知到瞬时的卡顿,延迟100-300ms则会让用户感觉到迟缓,300-1000ms的延迟让用户感觉“手机卡死了”,1000ms以上的延迟会让用户想去干别的事情了。什么是卡顿(Jank)
内容的快速加载很重要,渲染的流畅性也很重要。Android团队把滞缓,不流畅的动画定义为jank,一般是由于丢帧引起的。大部分Android设备一秒刷新屏幕60次(也有例外,比如早期的Android设备的刷新频率是50fps甚至更低)。由于屏幕每16ms刷新一次(1s/60fps = 16ms/f),所以保证每帧的渲染时间小于16ms是非常重要的。如果有一帧跳过了,用户将会感知到动画的跳跃,这样的体验是非常不好的。为了保证动画的流畅度,我们将研究如何使得整个屏幕在16ms内渲染完成。在这一章,我们将分析一些常见的问题,看看如何保证你的UI不出现卡顿。重要工具——层次结构查看器(Hierarchy Viewer)
为什么没有显示绘制时间
需要点击最右边的按钮。
三色点的意思是啥?
分别代表着 该view 在纵列的view层中measure,layout,draw 的相对速度。绿色表示其为速度快的50%,黄色表示为速度慢的50%,红色则表示其为该层最慢的view. 很显然,红色就是我们需要优化的目标。
优化注意点
一个视图的子视图越多,渲染就会越费时,减少视图树形结构的深度,App每一帧的渲染就会变快。RelativeLayout就需要经常对它的子View测量两次来确保所有子View被放置在了正确的位置。LinearLayout如果有子View设置了layout weight属性,也需要测量两次来确定子View的确切尺寸。如果是嵌套的LinearLayout或者是RelativeLayout,测量的次数将会呈指数增长(两层嵌套将会进行4次测量,3层嵌套会进行8次测量等等)
全部的测量、布局和绘制的时间最好在16ms以下,这样才能保证屏幕运行的流畅性。
从Tree overview中可以看到,屏幕上有很多个视图,渲染树的结构相对扁平。渲染树越扁平越好,因为视图XML文件的深度越深,渲染所需的时间就越长。然而,图中的结构虽然是扁平的,可还是需要26ms来进行绘制,说明扁平的结构也有可能会卡顿,也需要去考虑如何进行优化(正常情况16ms才算流畅)
消减资源
减少每个View所使用的资源也能减少时间消耗减少资源消耗方法之一:减少状态图片
重复绘制
检测工具之一:Debug GPU Overdraw
开发者选项菜单里增加了Debug GPU Overdraw的选项。如果你用的是Jelly Bean 4.3 或者 KitKat 设备,在屏幕的左下角会有一个计数展示屏幕overdraw的程度。我认为这个工具对快速检测overdraw问题还是十分有效的。* 白色:
没有overdraw
* 蓝色:
1次 overdraw(屏幕绘制了2次)
* 绿色:
2次 overdraw(屏幕绘制了3次)
* 浅红色:
3次 overdraw
* 深红色:
4次或者更多次overdraw
检测工具之二:Hierarchy Viewer中的overdraw
此时要关闭Debug GPU Overdraw ,开着Debug GPU Overdraw Hierarchy Viewer的内容就没有了Capture layers 另存为PSD , 免费的psd预览器 GIMP
然后可以用图层的形式来具体的看到重复绘制的情况。打开它真的需要耐心啊….
通过遍历图层,能大概了解图层重绘的情况,实际来看这种重绘的场景还是很少的。
KitKat(4.4)的Overdraw Avoidance
在KitKat或者更新版本的设备里,overdraw的影响被大幅度的削减了。这项技术被称为Overdraw Avoidance,系统可以自动地移除简单的overdraw(比如一个视图被其它视图完全覆盖住了)
分析卡顿的宏观工具Profile GPU Rendering
Android在Jelly Bean及更新的系统里加入了一个Profile GPU Rendering16ms的诅咒
绿色横线 是 16ms的诅咒,超过代表有卡顿。
绿色竖线 是当前画面绘制所到位置
每条竖线代表每次屏幕绘制draw(蓝色),prepare(紫色),process(红色),execute(黄色)
通过Logcat来看丢帧
内核级运行状态检测工具 Systrace
WASD键可以缩放(W,S)和左右滑动(A,D)。
VSYNC,由一些间隔均匀的宽条组成。VSYNC是告诉操作系统刷新屏幕的信号。每一条之间都间隔16ms(也就是中间的白色间隔)。当VSYNC事件触发的时候(在每个色条的尾部),surface flinger(红色高亮方框包含几种颜色的长条)会从view buffer(没展示出来)里选一个View,然后绘制到屏幕上。理想情况下,surfaceflinger会每隔16ms触发一次(没有jank的情况下),因此如果出现长条空缺则表明surfaceflinger丢掉了一次VSYNC更新——屏幕没有在规定的时间更新(这就导致jank的原因)。你可以看到在这段轨迹2/3的位置有这样一个间隔(在绿色方框中)。
* VSYNC-sf 提示surface flinger有16ms的时间来渲染屏幕。里面棕色的条状表示16ms的长度。
* surfaceflinger从队列里抓取一个View(注意黄色方框里的buffer中View数量从2变为1)。完成之后,View被发送给GPU,这样,屏幕绘制就完成了。
* VSYNC-app告诉app去渲染新的View(并且发送一个16ms的定时器)
* 当VSYNC一开始,droid.yahoo.att就不停的重复这个过程,测量View的布局,然后发送给RenderThread……循环往复。
从下图可以看出来,com.sankuai.meituan 产生了帧缓存,surfaceFlinger通过acquireBuffer获取到帧缓存,
接下来surfaceFlinger会将缓存数据交给GPU,然后将缓存队列中的帧缓存给release掉。并且com.sankuai.meituan所对应的绿色方块也没有了。
5.1的改进
每一帧都用一个标有F的圆点来表示。正常渲染的帧用绿色的圆点来表示,渲染慢(还有很慢的)的帧用黄色或者红色圆点来表示。选择圆点然后按下m就可以凸显出一帧的数据更易于分析。按下m键后,高亮显示该帧的区间来,连耗用的时间都标识出来。
警告提醒
总结:
systrace 还是很强大的,其从内核底层的角度反应整个系统的一系列运作,待后面更多的对底层知识的理解贯通后,还需多参考一下该工具。短时间的等待(1S内)不要使用Process进度条
相关文章推荐
- Android 属性动画(Property Animation) 完全解析 (下)
- [android] notification入门
- #号称5秒1000个包的超快速多渠道打包方式
- android实战开发02
- #号称5秒1000个包的超快速多渠道打包方式
- 聊聊Android应用实现跨进程调用
- Android开发规范——命名
- Volley详解
- Android 属性动画(Property Animation) 完全解析 (上)
- 让自己的软件出现在选择打开列表的软件中
- Android 开发艺术与探究 第一章 Activity 的生命周期和启动模式
- 电脑 (PC) Android 模拟器 - Genymotion 上安装 apk
- android 用gson解析遍历json数据
- Android中的Rect类——奇葩的思维
- Android APK反编译就这么简单 详解(附图)
- Android - ★★知识点
- Android RSA 加密出现Decryption error
- android 应用模式之mvp
- android 应用模式之mvp
- android 应用模式之mvp