Android的性能优化(上)

1.Android UI的渲染机制

当我们感觉到的流畅画面,需要的画面帧数要达到40帧到60帧每秒。而一帧的时间大约是16.67ms,换句话说,在1000ms的时间内,16.67ms大约就是现实60帧画面的单位时间。在Android系统中,系统是通过VSYNC信号触发对UI的渲染的,如果系统每次渲染的事件都保持在16.67ms以内,那么我们看到的UI界面将是非常的流畅的,这也就需要我们将所有程序的逻辑都保证在16ms之内,如果不能在16ms内完成绘制,那么就将造成丢帧的现象。即当前该重绘的帧被未处理完成的逻辑阻塞,例如一次绘制任务耗时20ms,那么在16ms系统发出的VSYNC信号就无法绘制,该帧就会被丢弃,等待下次信号擦次开始绘制,这就是画面卡顿的原因。

Android系统提供了检测UI渲染时间的工具,在“开发者选项中”有“GPU呈现模式分析”,选择“在屏幕上显示为条形图”,如下所示(本测试机为魅族,其他手机可能略有不同):

每一个条形图都包含有三部分,蓝色部分表示测量绘制Display List的时间,红色代表的是OpenGL渲染Display List所需要的时间,黄色代表的是CPU等待GPU处理的时间,中间的绿色横线代表的是VSYNC时间16ms,需要尽量将所有条形图都控制在这条绿线之下。

2.overDraw

overDraw表示的就是过度绘制,是指在一帧的时间内(16.67ms)像素被绘制了多次,理论上一个像素每次只绘制一次是最优的,但是由于重叠的布局导致一些像素会被多次绘制,而每次绘制都会对应到CPU的一组绘图命令和GPU的一些操作,造成CPU和GPU资源的浪费。在系统默认的绘制Activity的背景,如果再给布局绘制了重叠的背景,那么默认Activity的背景就是无效的过度绘制。

在我们的“开发者选项”中有这样一个检测工具“调用GPU过度绘制”,激活该功能之后可以通过界面上的颜色来判断overDraw的次数。

这个工具可以帮助我们检测当前区域的绘制次数,从而优化界面绘图层次,尽量增大蓝色的区域,减少红色的区域。

3.优化布局层次

在Android中,系统对View进行测量,布局和绘制时,都是通过对View数的遍历来进行操作的。如果一个View树的高度太高,就会严重影响到测量,布局和绘制的速度,因此,优化布局的第一个方法就会是降低View树的高度,Google也在API文档中建议View树的高度不宜超过10层。在现在的XML文件的根布局中,我们默认RelativeLayout来替换使用LineraLayout作为默认的根布局,其原因就是通过扁平的RelativeLayout来降低LineraLayout嵌套所产生的布局树的高度,从而提高UI的渲染速度。

1.使用 include 标签重用Layout

在一个应用程序的界面上,为了保持风格的统一,很多界面都会存在共通的UI,比如所说Topbar,Bottombar,Actionbar等等,如果在每一个界面上都进行赋值这一段共通的布局代码,不仅不利于后期代码的维护,还会增加程序的冗余。这时候就可以使用include标签来定义一这一个共通的UI。

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="0dp"
              android:layout_height="0dp"
              android:textSize="28sp"
              android:text="這是共通的UI界面"
              android:gravity="center">
</TextView>

在该共通的布局中,我将layout_width和layout_height设置为0dp,这样就迫使调用者在使用时必须对控件的狂傲进行赋值,否者是无法看见该控件的。

下一步就是如何使用该共通的UI布局了。只需要在使用该共通的UI布局文件中使用include标签的layout属性对这个共通的UI的ID的引用即可。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <include layout="@layout/commen_ui"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="20sp"
        android:text="你好你好你好"/>
</LinearLayout>

这时候如果我们要对布局中的属性进行赋值,就要重新覆盖某一项属性,进行赋值即可。效果如下:

2. 使用ViewStub实现view的延迟加载

使用ViewStub标签来实现对一个view的引用并且实现延迟加载。ViewStub是一个非常轻量级的组件,它不仅不可视,而且大小为0,下面来演示如何使用ViewStub来进行实现延迟加载的目的。

首先创建一个布局,这个布局在初始化加载时是不需要显示的,只有在某些情况下才需要进行显示的,例如查看用户信息的时候,只有点击了某一个按钮时,用户详细信息才显示出来。

当运行程序后,我们发现ViewStub中的布局确实没有显示出来,那么要如何才能重新加载显示的布局呢?

首先要通过findViewById()方法找到组件ViewStub。

mStub = (ViewStub) findViewById(R.id.vs_viewstub);
接下来就有两种方式显示这个view:
  1. VISIBLE

    通过调用ViewStub的setVisiblity()方法来显示这个view.代码如下:

mStub.setVisibility(View.VISIBLE);
  1. INFLATE

    通过调用ViewStub的inflate()方法来显示这个view.代码如下:

View inflate = mStub.inflate();

这两种方式都是可以将ViewStub重新进行展开,显示引用的布局,而唯一的区别在于就是inflate()可以返回引用的布局,从而可以通过View.findViewById()方法来找到对应的控件。

View inflate = mStub.inflate();
        TextView textview = (TextView) inflate.findViewById(R.id.textview);
        textview.setText("我是点击后加载的");

注意:不管只用那种方式,一旦ViewStub被设置可见或者是inflate之后,ViewStub就不存在了,不能被反复的inflate,取而代之的就是被inflate的Layout,并将这个Layout的ID重新设置为ViewStub中通过android:inflateId属性所指定的ID,这也就是为什么两次点击之后会报错的原因:如下所示:

Caused by: java.lang.IllegalStateException: ViewStub must have a non-null ViewGroup viewParent

简要说明View.GONE和ViewStub标签的区别是什么?共同点都是初始时都不会显示,但是ViewStub标签只会在显示时才会去渲染整个布局,而View.GONE,在初始化布局树的时候就已经添加在布局树文件中了,相比之下ViewStub的效率会更高。

如下图所示:

4.hierarchyviewer.bat

hierarchyviewer.bat是无法在真机上进行使用的,只能在模拟器上使用或者是原生的模拟器上使用,也就是没有加密的设备上。当然真机上也是可以用的,可以到github上下载一个开源项目View Server,下面在模拟器上使用hierarchyviewer.bat。

hierarchyviewer.bat位于sdk\tools目录下,直接双击即可启动,如下:

注意:我们在使用hierarchyviewer的时候,一定要是模拟器是打开的,这样才能在hierarchyviewer中看到我们要显示的布局文件。

下面我们写一个非常冗余的布局进行显示文件,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="你好啊啊 啊啊啊啊 啊"
                android:textColor="#efff0019"
                android:textSize="20sp"/>
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

这个布局文件是三层LinearLayout嵌套之后里面装了一个button,很显然这些LinearLayout都是冗余的,利用hierarchyviewer可以打开这个布局文件,如下图所示:

通常情况下,我们只关注ID为content的Framlayout的分支,这也是setContentView()设置的内容,可以很明显的看出在layout布局文件中(红色布局),这三层LinearLayout没有任何的分支,说明是冗余嵌套,可以直接去掉的。

当点击其中一个view的时候,可以显示view的绘制情况的,不过第一次点击的时候各种显示的事件都是n/a,需要点击菜单中的Profile Node按钮重新进行计算,才能回去到绘制信息。在系统的右下方会给出不同颜色的小圆点,用来表示绘制的效率,绿黄红分别代表的是好中差的绘制效率。

时间: 2024-11-06 14:54:04

Android的性能优化(上)的相关文章

Android开发性能优化总结(一)

安卓开发应用首先要讲究良好的用户体验,如果一款软件卡顿现象严重,不流畅,经常崩溃,那么将给用户带来极不良好的体验,从而损失用户. 在实际开发和学习中,我总结了一下关于安卓性能的优化,供大家参考交流. 应用程序的性能问题体现在很多方面, 比如第一次启动速度慢,或者进入某一界面速度慢:动画执行过程不流畅,或者动画执行卡顿时间长:ListView列表滑动过程中卡顿,不流畅:应用程序自定义的某特定界面执行速度慢:响应某一用户事件时长时间无响应(ANR):操作数据库时,执行大量数据的增删改查操作,执行速度

Android客户端性能优化(魅族资深工程师毫无保留奉献)

本文由魅族科技有限公司资深Android开发工程师degao(嵌入式企鹅圈原创团队成员)撰写,是degao在嵌入式企鹅圈发表的第一篇原创文章,毫无保留地总结分享其在领导魅族多个项目开发中的Android客户端性能优化经验,极具实践价值! 即日起,嵌入式企鹅圈将在之前五个专栏(Linux内核驱动情景分析.资源紧缺型SOC嵌入式架构设计.嵌入式交叉工具链及其应用.嵌入式设计和编程.微信硬件平台和物联网解决方案)新增Android开发专栏!更多Android.Linux.嵌入式和物联网原创技术分享敬请

Android应用性能优化

遇到的问题: 1)ANR 2)ListView 卡顿,不流畅 3)Activity启动慢 4)动画不流畅,启动前卡顿 5)自定义view启动慢 6)  OOM 7)数据库大量操作 8)长时间运行后,程序变慢 基本思想: 1)语言层解决问题,语法上提高性能 2)合理的数据结构和算法 3)布局优化,布局深度控制 4)工作线程与UI线程分离 5)合理的缓存机制 6)NDK合理使用 7)优化的SQL语句 8)使用工具,分析问题找出瓶颈 优化工具: view优化工具:hierarchy view 代码优化

Android应用性能优化系列视图篇——隐藏在资源图片中的内存杀手

图片加载性能优化永远是Android领域中一个无法绕过的话题,经过数年的发展,涌现了很多成熟的图片加载开源库,比如Fresco.Picasso.UIL等等,使得图片加载不再是一个头疼的问题,并且大幅降低了OOM发生的概率.然而,在图片加载方面我们是否可以就此放松警惕了呢? 开源图片加载库能为我们解决绝大部分有关图片的问题,然而并不是所有! 首先,图片从来源上可以分成三大类:网络图片.手机图片.APK资源图片.网络图片和手机图片都在图片加载库功能的覆盖范围内,基本上不用开发者太操心,但是APK资源

Android开发性能优化总结(二)

接上一篇<Android开发性能优化总结(一)> 一.安卓UI性能检测与优化 UI是安卓应用程序与用户打交道的最直接途径,UI设计的好不好,直接影响到用户的体验,如果没有达到他们心目中的自然流畅细节,用户要是能够感觉出来,少则影响心情,多则卸载应用:所以一个应用的UI显示性能问题就不得不被开发人员重视. 1.UI卡顿常见原因: 在UI线程中做了耗时操作,导致UI线程卡顿: 布局Layout过于复杂,无法在16ms内完成渲染: 同一时间动画执行的次数过多,导致CPU或GPU负载过重: View过

Android app 性能优化之视图优化

Android app 性能优化之视图优化 前言: 每当一款App开始快速扩展的时候,随着业务功能的越来越复杂,功能模块的越来越多总会引起这样那样的性能问题.交互不流畅卡顿,ANR,手机发热量大等等性能问题在Android开发中一直都是一个坑爹的存在.不是大家不想去优化,可能是等你发现开始要搞搞性能的时候,发现工程貌似好大了,能跑不崩就万事大吉了,那么多代码要去看,去改.真心是一个让人想想都糟心的事.也可能,关键点不好找,可能一个性能问题是别的你想都想不到的地方引起的,为了优化这么一个点,可能花

Android内存性能优化(内部资料总结) eoe转载

刚入门的童鞋肯能都会有一个疑问,Java不是有虚拟机了么,内存会自动化管理,我们就不必要手动的释放资源了,反正系统会给我们完成.其实Java中没有指针的概念,但是指针的使用方式依然存在,一味的依赖系统的gc,很容易就造成了内存的浪费. Java基于垃圾回收的内存机制 Java的内存管理机制会自动回收无用对象所占用的内存,减轻手工管理内存的负担 1.C/C++: 从申请.使用.释放都需要手工管理 2.Java:无用的对象的内存会被自动回收 什么样的对象是无用的对象 1.Java通过引用来操作一个具

Android代码性能优化技巧 (一)

转载自 http://blog.csdn.net/leilu2008/article/details/6672979 我们大家都知道Android 2.2的JIT性能有了本质的提高,不过对于老版本的程序提高Java执行效率还有很多语言特点来说,对于Java 1.5之后将会有明显的改进.下面的例子来自SDK: [java] view plaincopy static class Foo { int mSplat; } Foo[] mArray = ... //上面的静态类Foo的执行效果和性能,我

Android APP 性能优化的一些思考

说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才感觉运行速度稍微提高了点,就算手机在各种性能跑分软件面前分数遥遥领先,还是感觉无论有多大的内存空间都远远不够用.相信每个使用 Android 系统的用户都有过以上类似经历,确实,Android 系统在流畅性方面不如 IOS 系统,为何呢,明明在看手机硬件配置上时,Android 设备都不会输于 IO

Android app 性能优化的思考--性能卡顿不好的原因在哪?

说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才感觉运行速度稍微提高了点,就算手机在各种性能跑分软件面前分数遥遥领先,还是感觉无论有多大的内存空间都远远不够用.相信每个使用 Android 系统的用户都有过以上类似经历,确实,Android 系统在流畅性方面不如 IOS 系统,为何呢,明明在看手机硬件配置上时,Android 设备都不会输于 IO