• 程序性能优化之布局检测与优化(二)上篇


    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680
    本篇文章将先从以下三个内容来介绍布局检测与优化:

    • [布局层级优化]
    • [过度渲染]

    一、布局层级优化

    程序的每个组件和 Layout 都需要经过初始化、布局和绘制,如果布局嵌套层次过深,就会导致加载操作更为耗时,更严重的话还可能导致内存溢出。本节我们学习使用两个工具来检查和优化 Layout。

    HierarchyViewer

    该工具位于Android SDK tools中,使用HierarchyViewer可以分析正在运行app的布局,从而打破影响布局性能的瓶颈。

    HierachyViewer通过选择运行在模拟器或真机上的进程来工作,并通过布局树来展示。上面每个标识代表布局的Measure、Layout和Draw的性能,帮助开发者来定位潜在的问题。

    如图1所示,图中是ListView中的一条布局,这个布局左边是一个ImageView,右边是一个LinearLayout中嵌套两个TextView布局。

     
    19956127-d8c0a3b8a942a61a
     

    图1

    HierarchyView工具可以用于Android模拟器,打开后,即可看到可用设备列表和运行的组件。在Windows选项卡里,点击Hierarchy View后,即可看到选择组件的布局层次结构。例如图2 展示了图1 的ListItem布局的层次结构。

     
    19956127-2c27c0df4058048a
     

    图2

    减少层次结构

    由于上图使用了嵌套的LinearLayout结构布局,导致性能变慢。我们可以使用扁平化的思想来优化它们——布局要宽而广,而不是窄而深! 我们可以使用Relativelayout来作为顶级节点,这样转向RelativeLayout来布局之后,我们会看到下图这样的布局层级结构。

     
    19956127-12a207750a5cd8c6
     

    图3

    修改为RelativeLayout布局之后,层级减少,布局性能大大增强。另外,LinearLayout中的layout_weight也会减慢measure的速度,所以不是必要时不要使用layout_weight属性。这只是一个小小的例子,在一些非常复杂的布局中,如果层级太多或LinearLayout嵌套过多,系统会将很大性能消耗在UI的measure计算上面,因此,层级结构优化至关重要。

    Lint

    Android Lint是在 ADT 16 提供的新工具,它是一个代码扫描工具,Lint已经替代了Layoutopt tool成为重要的提示工具,它具有更多更高级的功能 ,能够帮助我们识别代码结构存在的问题。Lint 包含的一些检测规则有:

    • 使用 compound drawable 替代一个包含 ImageView 和 TextView 的 LinearLayout。

    • 合并根 FrameLayout

    • 没用的子节点或父节点

    • 硬编码问题

    另外,开发者可以通过 File>Settings>Project Settings 来管理配置文件。

     
    19956127-13912fb7466368f8
     

    二、过度渲染

    一、androidUI过度渲染概述

    1、从android卡顿说起

    通常我们可以从各种渠道听到用户反馈app卡顿,究竟是什么用户觉得卡顿呢?因为大多数手机的屏幕刷新频率是60hz,如果在1000/60=16.67ms内没有办法把这一帧的任务执行完毕,就会发生丢帧的现象。丢帧越多,用户感受到的卡顿情况就越严重。

     
    19956127-9e82cf38e8f6a5bd.png
     

    所以,可以看出更新每一帧耗时至关重要,说道每一帧图像的更新过程不得不提到GPU和CPU。CPU负责包括Measure,Layout,Record,Execute的计算操作,GPU负责Rasterization(栅格化)操作。例如显示图片的时候,需要先经过CPU的计算加载到内存中,然后传递给GPU进行渲染。一旦GPU或者CPU的工作超过了规定事件,就会出现app卡顿现象。比如:

    (1)GPU耗时导致卡顿原因:通常与画面的渲染有关,比如界面存在严重的过度渲染,渲染高清大图等,与UI View的渲染方法如draw()、onDraw()、dispatchDraw()等关联。

    (2)CPU的耗时导致卡顿原因:主要是由于UI线程有耗时较久的操作,比如处理大图片、进行耗时的IPC通信等,自然会拖长UI线程处理的时间。UI线程通常会运行以下方法: 渲染相关方法; UI布局相关方法:

    onMeasure(),onLayout();

    Handler: handleMessage();

    post(Runnable);

    Activity相关方法, 如:

    onCreate(),onResume(),onStar(),onStop()等。

    2、再谈过度渲染

    Overdraw(过度渲染)是指的手机屏幕上的一个像素点在一帧更新时间内被绘制了多次,我们就认为试过绘制了。显然过渡绘制发生时,在UI层次中处于被遮挡的绘制是不可见的,也是对资源的浪费。用一个简单的例子,好比我们刷墙,刷了一层又一层,最终能看到的墙还是最后一次刷上去的样子。

     
    19956127-82afc1f3623c66ab.png
     

    既然过度渲染问题严重,那么如何发现是否有过度渲染存在呢?google在安卓4.4系统中开发了查看过度渲染计数的入口,在开发者选项中,打开GPU调试,选择过度渲染计数,屏幕左下方可以看到当前窗口过度渲染计数。如手机管家7.0主页过度渲染计数。

    具体的数值代表的意义为:

    蓝色:1倍过度绘制,1.X;

    绿色:2倍过度绘制,2.X;

    淡红色:3倍过度绘制,3.X;

    红色:4倍或以上过度绘制, 4.X。

     
    19956127-179ba34378630b20.png
     

    二、自动化测试方案

    既然能够通过系统设置知道过度渲染次数,测试时候就读取该值,填写报告就完了啊,为何要自动化呢?因为在对app进行系统的测试时,会发现页面非常多,如管家一二级页面就多大20多个,且集成包,灰度包,正式包,回归包都要进行一次测试,所以进行自动化过度渲染计数读取是有必要的。

    1、获取页面过度渲染计数

    (1)HOOK系统方法,读取过度渲染计数。

    通过查看安卓4.4的源码,可以知道在Framework/base/core/Java/android/view/

    HardwareRender.java中有一个叫做GLRenderer的内部类,该类还有一个方法如下:

     
    19956127-55e7c5e30400e3a6.png
     

    我们能够hook该方法,抓取入参overdraw并打印到日志,就是我们需要的过度渲染计数。

     
    19956127-b2686954498e5577.png
     

    【难点】

    1)如何hook内部类的方法:在外部类和内部类之间添加 $符号定位内部类;

    2)如何构造一个隐藏的参数类型,如上述HardWareCanvas:直接使用包名加类名定位该类型。

    通过hook的方法输出的过度渲染计数来源于系统调用API,所以什么时候能拿到这个值不受人为控制,使用者只能等待系统日志输出,这也是hook技术的通病,为此我们引入第二种方法。

    (2)反射系统过度渲染计数的类,输出过度渲染计数。

    系统在屏幕中绘制过度渲染计数时,是通过drawText绘制到屏幕上(上述(1)方法的源码截图看出),所以找到调用绘制方法的类,就可以得到过度渲染计数,同样在HardwareRenderer.java代码中debugOverdraw调用了绘制的方法,该方法也是过度渲染计数获取的方法。

     
    19956127-d3e962d1c123d46e.png
     

    注:以上方法都是通过系统函数获取过度渲染计数,所以测试时,必须打开设置中的过度渲染计数。

    2、实现自动化测试

    (1)在什么时候读取页面overdrawcounter值?

    页面从创建到销毁,什么时候页面才是最绘制最稳定的时候呢?我们假设页面上有需要下载的资源,需要耗时才能获取的资源等,所以只有在页面消失前一刻,我们才认为此时页面相对绘制最完整。所以跟进安卓生命周期,我们在onPause()时来读取过度渲染计数。

     
    19956127-92fbfa91f44a9ad0.png
     

    (2)如何实现自动化呢?

    因为在调用onPause()时候会自动读取过度渲染值,所以我们要做的自动化仅仅是如何在被测页面之间切换,搜集各个页面的过度渲染值,输出报告,所以流程可以归纳为:

     
    19956127-224df2aa4aa37542.png
     

    三、测试收益

    1、整个测试方案在手机管家7.0中运行起来,对集成包,灰度包,正式包的一二级页面进行了过度渲染测试,优化后管家正式包一二级页面平均过度渲染计数为2.4X,小于管家标准3.0X。

    报告样例为:

     
    19956127-db9879eeacbcaa18.png
     

    2、对手机管家22个基础页面监控,到正式版发布时全部页面过度渲染计数都小于3.0X。下图为管家部分页面优化前后对比。

    管家主界面:

     
    19956127-1c55440d1d6321d6.png
     
     
    19956127-3fe6f57555c49488.png
     

    体检优化界面:

     
    19956127-1e759fc12494e37e.png
     
     
    19956127-40bfb1a7fe73cb76.png
     

    个人中心页面:

     
    19956127-64971a6a49822096.png
     
    19956127-1eb2361e67632c13.png
     

    3、问题页面优化前后过度渲染计数对比

     
    19956127-5d01d649209ad584.png
     


    原文作者:陈诚
    原文链接:https://cloud.tencent.com/developer/article/1005333
    参考https://www.cnblogs.com/net19880504/p/6412644.html
    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680

  • 相关阅读:
    个人学习进度(第十二周)
    第一阶段冲刺(第九天)
    搜狗输入法用户体验
    第一阶段冲刺(第八天)
    第一阶段冲刺(第七天)
    Fliter(过滤器)的认识
    一、python运算符
    virtualenv虚拟环境
    Linux命令(二)
    Linux命令(一)
  • 原文地址:https://www.cnblogs.com/Android-Alvin/p/11958555.html
Copyright © 2020-2023  润新知