Android性能优化——布局优化

1.Android UI渲染机制

人眼所感觉的流畅画面,需要画面的帧数达到40帧每秒到60帧每秒,最佳的fps大概是在60fps左右,这是评价一个显卡性能高低的标准之一。

fps:Frame(画面、帧) per second。就是指动画或视频的画面数,每秒的帧数越多,就画面越流畅。当fps太低时,我们肉眼就能明显感觉到屏幕的闪烁,不连贯,图像显示效果和视觉效果很差。

在Android中,系统通过VSYNC信号触发对UI的渲染、重绘。其间隔时间是16ms。这个16ms就是1000ms(1s)中显示60帧画面的单位时间,即1000/60.(每16ms就会显示一帧)如果系统每次渲染的时间都保持在16ms之内,那么我们看见的UI界面将会非常流畅,这也就需要将所有程序的逻辑都保证在16ms内。如果不能再16ms内完成绘制,那么则会出现丢帧的现象,即当前该重绘的的帧被未完成的逻辑阻塞,例如,一次绘制任务耗时20ms,那么在16ms系统发出VSYNC信号时就无法绘制,该帧就会被丢弃,等待下次信号才开始绘制,导致16ms*2内部显示的是同一帧的画面,这就是画面卡顿的原因。

GPU:图形处理器,是显卡的“心脏”,主要负责显示图形。

2.避免Overdraw

Overdraw,过度绘制会浪费很多的CPU,GPU资源。

例如,系统默认绘制Activity的背景,而如果再给布局绘制重叠的背景,那么默认Activity的背景就属于无效的过度绘制——Overdraw。

通过开发者选项中——显示GPU过度绘制,可以通过界面的颜色查看Overdraw的绘制次数,从而尽量优化绘图的层次,尽量增大蓝色的区域,减少红色的区域。

3.优化布局层级

在Android中,系统对View进行测量、布局和绘制时,都是通过view树的遍历来进行操作的。如果一个view树的高度太高,就会严重影响测量、布局和绘制的速度因此优化布局的第一个方法就是降低View树的高度,官方API建议View树的高度不宜超过10层。

在早期的Android版本中,使用LinearLayout作为默认的根布局,现在已经使用RelativeLayout来代替LinearLayout作为默认的根布局,就是通过扁平的RelativeLayout来降低通过LinearLayout嵌套所产生的布局树的高度,从而提高UI渲染的效率

4.避免嵌套过多无用的布局

嵌套的布局只会让view树的高度越来越高,因此在布局时,需要根据自身不同的特点来选择不同的Layout组件,避免嵌套的发生

    1>使用<include>标签重用Layout

在一个应用程序中,为了风格上的统一,很多界面都会存在一些共同的UI,比如一个应用的Toolbar、Bottombar等。对于这些共同的UI,如果在每个界面都来复制一段这样的代码,不仅不利于后期代码的维护,更增加了程序的冗余度。因此可以用<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="30sp"
    android:gravity="center"
    android:text="this is a common ui">
</TextView>
 注意:将android:layout_height和android:layout_width设置为0dp,这样就迫使开发者在使用时对宽和高进行赋值,否则无法看见 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity" 
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <TextView
        android:text="HelloWorld"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
    <include layout="@layout/common_ui"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true" />
</RelativeLayout>

 
 
注意:如果你需要在<include>标签中覆盖类似原布局中的android:layout_XXX的属性,就必须在<include>标签中同时指定<pre name="code" class="html">android:layout_height和android:layout_width属性
 
 
2>使用<ViewStub>实现对View的延迟加载(只有在要显示的时候才会被渲染) 

除了把一个view作为共通UI,并通过<include>标签来进行应用之外,还可以使用<ViewStub>标签实现对一个View的引用并实现迟加载。<ViewStub>是一个非常轻量级的组件,它不仅不可视,并且大小为0.

not_often_use.xml

<?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">
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="not often use layout"
        android:textSize="30sp"/>

</LinearLayout>
 

 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Visible"
        android:onClick="btnVisible"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Inflate"
        android:onClick="btnInflate"
        android:id="@+id/button2"
        android:layout_alignBottom="@+id/button1"
        android:layout_toEndOf="@+id/button1"/>
    <ViewStub
        android:id="@+id/not_often_use"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:layout="@layout/not_often_use"/>
</RelativeLayout>
 通过引用将not_often_use放在ViewStub中 
 在运行程序以后,<ViewStub>中引用的布局并没有显示出来,那么怎么才能加载出布局呢?? 

先找到<ViewStub>组件

mViewStub = (ViewStub)findViewById(R.id.not_often_use);

有两种方法:

*VISIBLE

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

mViewStub.setVisibility(View.VISIBLE);*inflate

通过调用inflate()方法显示这个view,代码如下:

View inflateView = mViewStub.inflate();

这个方法可以返回引用的布局。通过findViewById找到布局里面的空间,并可以进行设置

View inflateView = mViewStub.inflate();
TextView textView = (TextView)inflateView.findViewById(R.id.tv);
textView.setText("HAHA");
 

不管使用哪种方法,一旦ViewStub被设置为可见了或是被inflate了,ViewStub就不在了,取而代之的就是被inflate的Layout.

总结:ViewStub只会在显示时,才会渲染整个布局。

那么View.GONE和ViewStub有什么区别呢??

答:它们的共同点就是初始化的时候都不显示,但是ViewStub只有在显示的时候才会渲染布局,而View.GONE,在初始化布局树的时候就已经添加在布局树中了,相比之下,ViewStub的效率更高

5.Hierarchy Viewer

Hierarchy Viewer无法在真机上进行使用它只能在工厂的demo机和模拟器上使用。

通过这个工具,就会很快的找到view树中的冗余布局,从而有效的优化布局。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值