android性能优化 布局优化
2017-07-06 14:19:45 baidu_35255405 阅读数 98


先广泛的说一下性能优化,如果是后台开发的话,内存溢出以及耗时算法可能引起性能上的问题。如果是移动端的开发的话,就多了这么一条,多了这么一层UI渲染。好吧,开头就是泛泛地说一下,那么,今天这篇博客的内容主要就是针对UI渲染上的优化。

2015年的时候,Google发布了Android性能优化典范专题 。都是以短视频的形式,来帮助我们开发人员开发出更好的Android App。如果有兴趣的同学,可以自行搜索引擎。


Android的渲染机制:(PS:下面的介绍摘自开源中国:http://www.oschina.net/news/60157/android-performance-patterns)

希望你们可以去看这篇文章。


下面主要谈一下这几个标签,在布局中的使用会提升渲染的性能。


1,include 标签

将外部布局文件引入到当前布局文件,适用于多界面频繁出现的相同布局,来实现布局的模块换。


2,viewstub 标签

同include标签相似,将外部布局引入到当前布局,与之不同之处,由该标签引入的布局默认不会扩张,即不占用位置,不展示,在UI渲染的时候后,节省CPU和内存。通常用于默认不展示的View ,当某个事件的发生,从而引起他的展示, 例如,网络连接断开,网络请求

在java中通过(ViewStub)findViewById(id)找到ViewStub,通过stub.inflate()展开ViewStub,然后得到子View,如下:

private View networkErrorView;

private void showNetError() {
	// not repeated infalte
	if (networkErrorView != null) {
		networkErrorView.setVisibility(View.VISIBLE);
		return;
	}

	ViewStub stub = (ViewStub)findViewById(R.id.network_error_layout);
	networkErrorView = stub.inflate();
	Button networkSetting = (Button)networkErrorView.findViewById(R.id.network_setting);
	Button refresh = (Button)findViewById(R.id.network_refresh);
}

private void showNormal() {
	if (networkErrorView != null) {
		networkErrorView.setVisibility(View.GONE);
	}
}

在上面showNetError()中展开了ViewStub,同时我们对networkErrorView进行了保存,这样下次不用继续inflate。这就是后面第三部分提到的减少不必要的infalte。

viewstub标签大部分属性同include标签类似。


ViewStub stub = (ViewStub)findViewById(R.id.network_error_layout);
networkErrorView = stub.inflate();

3,merge

merge标签可用于两种典型情况:
a.  布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容试图的parent view就是个FrameLayout,所以可以用merge消除只剩一个。
b.  某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。



2016-10-01 17:42:07 luulmm520 阅读数 672

布局优化:就是尽量减少布局文件的层级,致使Android的绘制的工作量减少了,性能就提高啦。

第一种
首先删除布局中无用的控件和层级,其次有选择性的使用性能较低的ViewGroup。
比如RelativeLayout. 如果布局中即可以使用RelativeLayout和LinerLayout 那么优先选择 后者,因为RelativeLayout功能比较复杂,会消耗较多的cpu时间。
FrameLayout和LinerLayout 是一样的一种简单高效的ViewGroup 。当单一使用这两者无法实现效果时,需要嵌套时候,建议使用RelativeLayout.这是由于ViewGroup的嵌套就相当于增加了布局的层级,同样会降低程序的性能。

第二种

采用 标签<include>和标签<merge> 还有ViewStub.
<include>标签用于布局重用,一般和<merge>标签配合使用, 可以减低布局层级。
ViewStub 主要是提供了按需加载的功能,当需要时才会将ViewStub的布局加载到内存中, 提高程序初始化效率。

<include>标签的应用

这里写图片描述

这里写图片描述

<merge>标签的应用

这里写图片描述

例如LinerLayout 水平 布局中 需要嵌套另一个 水平布局的LinerLayout 那么就可以用<merge>标签代替。

ViewStub
ViewStub 继承了View ,它是非常轻量级 而且 高/宽都是0,应为它本身不参与任何布局和绘制, 按需分配的,神马意思呢,比如我们网络加载异常的时候,这个时候需要加载进来。网络正常时,没有必要在整个界面进行初始化。

这里写图片描述

(ViewStub)findviewById(R.id.stub_import).setVisibility(View.VISIBLE);方法来初始化。
或者 View importPanel=((ViewStub)findviewById(R.id.stub_import)).inflate();

注意: 目前 viewStub 还不支持<merge>

2019-01-01 13:16:00 weixin_33712987 阅读数 39
屏幕UI刷新机制:

如果我们要保证屏幕流程的运行就需要保证UI的测量,布局和绘制的时间在16毫秒内,因为人眼与大脑之间的协作无法感知超过60帧的画面更新,而16毫秒也就是每秒刷新60帧,1000毫秒除以60帧约等于16毫秒,也就是说如果超过16毫秒每帧用户就会明显感知到!

  • 刷新率(refresh rate):指在一秒内刷新屏幕的次数,例如(60HZ)
  • 帧率(frame rate):指GPU在一秒内操作画面的帧数,例如(30fps,60fps)
UI刷新的过程:
5439590-b81c7b22bb58faf7.png
UI刷新的过程

CPU和GPU负责处理数据 交给buffer 而display也就是我们的显示器会每隔一段时间就去buffer中取数据然后显示处理!
而实际情况是CPU及GPU存入数据的时间和display取数据的时间并不能保证是一致的,针对这种情况android引入了VSYNC(垂直同步)机制也就是帧同步,他是为了保证GPU生成帧的速度和display刷新的速度保持一致,android系统会每隔16毫秒就发出一次VSYNC的信号触发UI的渲染更新,只有收到了VSYNC的信号后才能进行UI的绘制!
VSYNC的主要作用就是为了防止画面撕裂的情况出现,也就是帧率超过刷新率会出现的情况


5439590-12a960a108bdd3ca.png
画面撕裂的情况

图一是出现画面撕裂的情况,图二是画面卡顿的情况:


5439590-e0392b8341964668.png
image.png
布局的选择
  • FragmentLayout能实现的优先使用FragmentLayout(因为它的源码是最小的,也是最高效的)
  • ConstraintLayout大约比RelativeLayout的效率更高处40%
  • 优先选择RelativeLayout
  • 当在RelativeLayout和LinearLayout不嵌套的情况下能满足需求是优先选择LinearLayout
重复绘制:

重复绘制并不是指绘制错误,RelativeLayout会对UI测量2次以确保所有的子视图被放置了正确的位置,如果LinerLayout子视图放置了width属性那么LinerLayout也需要测量2次,如果嵌套的RelativeLayout和LinerLayout会乘子数增长,2层嵌套会测量4次,3层嵌套会进行8次测量等等!

overDraw过度绘制
  • overDraw是指屏幕上某一个像素点在同一帧的时间绘制了多次
    可以在手机的设置-开发者选项-打开GPU调试过度绘制来查看过度绘制的情况


    5439590-6aea94c3a2db71c2.png
    image.png

优化标签的使用

  • include 目的是提高代码的复用性,减少代码;将布局中公共部分抽取供其他layout使用
  • merge include标签的辅助扩展,解决布局层级的优化,减少布局嵌套的层次,提高布局加载的效率
    merge 的2个特点:1根标签必须是merge 2merge 的属性是使用的父布局的属性
  • View stub 只有加载该布局的时候才占用资源,Invisible状态是不会绘制出来的!没有大小没有绘制功能,也不参与布局,资源消耗非常低
2014-04-18 10:45:13 niejing654092427 阅读数 589


转载: http://www.trinea.cn/android/layout-performance/


在Android开发中,我们常用的布局方式主要有LinearLayout、RelativeLayout、FrameLayout等,通过这些 布局我们可以实现各种各样的界面。与此同时,如何正确、高效的使用这些布局方式来组织UI控件,是我们构建优秀Android App的主要前提之一。本篇内容就主要围绕Android布局优化来讨论在日常开发中我们使用常用布局需要注意的一些方面,同时介绍一款SDK自带的UI 性能检测工具HierarchyViewer。

布局原则

通过一些惯用、有效的布局原则,我们可以制作出加载效率高并且复用性高的UI。简单来说,在Android UI布局过程中,需要遵守的原则包括如下几点:

  • 尽量多使用RelativeLayout,不要使用绝对布局AbsoluteLayout;
  • 将可复用的组件抽取出来并通过< include />标签使用;
  • 使用< ViewStub />标签来加载一些不常用的布局;
  • 使用< merge />标签减少布局的嵌套层次;

由于Android的碎片化程度很高,市面上存在的屏幕尺寸也是各式各样,使用RelativeLayout能使我们构建的布局适应性更强,构建出 来的UI布局对多屏幕的适配效果越好,通过指定UI控件间的相对位置,使在不同屏幕上布局的表现能基本保持一致。当然,也不是所有情况下都得使用相对布 局,根据具体情况来选择和其他布局方式的搭配来实现最优布局.

1、抽象布局标签 

(1) <include>标签
include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,这在布局编写方便提供了大大的便利。
下面以在一个布局main.xml中用include引入另一个布局foot.xml为例。main.mxl代码如下:

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

    <ListView
        android:id="@+id/simple_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="@dimen/dp_80" />

    <include layout="@layout/foot.xml" />

</RelativeLayout>


其中include引入的foot.xml为公用的页面底部,代码如下:


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

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40"
        android:layout_above="@+id/text"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40"
        android:layout_alignParentBottom="true"
        android:text="@string/app_name" />

</RelativeLayout>


<include>标签唯一需要的属性是layout属性,指定需要包含的布局文件。可以定义android:id和android:layout_*属性来覆盖被引入布局根节点的对应属性值。注意重新定义android:id后,子布局的顶结点i就变化了。

接着我们进入sdk目录下的tools文件夹下,找到HierarchyViewer并运行(此时保持你的模拟器或真机正在运行需要进行分析的App),双击我们正在显示的这个App所代表的进程。




接下来便会进入hierarchyviewer的界面,我们可以在这里很清晰看到正在运行的UI的布局层次结构以及它们之间的关系。

分析刚刚我们构建的导航栏布局,放大布局分析图可以看到,被include进来的footer.xml根节点是一个RelativeLayout,而包含它的主界面main.xml根节点也是一个RelativeLayout,它前面还有一个FrameLayout等几个节点,FrameLayout就是Activity布局中默认的父布局节点,再往上是一个LinearLayout,这个LinearLayout就是包含Activity布局和状态栏的整个屏幕显示的布局父节点,这个LinearLayout还有一个子节点就是ViewStub,关于这个节点我们在后面会详细介绍。


 

(2) <merge>标签
在使用了include后可能导致布局嵌套过多,多余不必要的layout节点,从而导致解析变慢,不必要的节点和嵌套可通过hierarchy viewer(下面布局调优工具中有具体介绍)或设置->开发者选项->显示布局边界查看。

 

merge标签可用于两种典型情况:
a.  布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容试图的parent view就是个FrameLayout,所以可以用merge消除只剩一个。
b.  某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。

以(1) <include>标签的示例为例,用hierarchy viewer查看main.xml布局如下图:

可以发现多了一层没必要的RelativeLayout,将foot.xml中RelativeLayout改为merge,如下:

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

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40"
        android:layout_above="@+id/text"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40"
        android:layout_alignParentBottom="true"
        android:text="@string/app_name" />

</merge>


运行后再次用hierarchy viewer查看main.xml布局如下图:

这样就不会有多余的RelativeLayout节点了。

2、去除不必要的嵌套和View节点
(1) 首次不需要使用的节点设置为GONE或使用viewstub
(2) 使用RelativeLayout代替LinearLayout
大约在Android4.0之前,新建工程的默认main.xml中顶节点是LinearLayout,而在之后已经改为RelativeLayout,因为RelativeLayout性能更优,且可以简单实现LinearLayout嵌套才能实现的布局。
4.0及以上Android版本可通过设置->开发者选项->显示布局边界打开页面布局显示,看看是否有不必要的节点和嵌套。4.0以下版本可通过hierarchy viewer查看。

 

3、减少不必要的infalte
(1) 对于inflate的布局可以直接缓存,用全部变量代替局部变量,避免下次需再次inflate
如上面ViewStub示例中的

if (networkErrorView != null) {
	networkErrorView.setVisibility(View.VISIBLE);
	return;
}



(2) ListView提供了item缓存,adapter getView的标准写法,如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
	ViewHolder holder;
	if (convertView == null) {
		convertView = inflater.inflate(R.layout.list_item, null);
		holder = new ViewHolder();
		……
		convertView.setTag(holder);
	} else {
		holder = (ViewHolder)convertView.getTag();
	}
}

/**
 * ViewHolder
 * 
 * @author trinea@trinea.cn 2013-08-01
 */
private static class ViewHolder {

	ImageView appIcon;
	TextView  appName;
	TextView  appInfo;
}


关于ListView缓存原理可见Android ListView缓存机制

4、其他点
(1) 用SurfaceView或TextureView代替普通View

SurfaceView或TextureView可以通过将绘图操作移动到另一个单独线程上提高性能。
普通View的绘制过程都是在主线程(UI线程)中完成,如果某些绘图操作影响性能就不好优化了,这时我们可以考虑使用SurfaceView和TextureView,他们的绘图操作发生在UI线程之外的另一个线程上。
因为SurfaceView在常规视图系统之外,所以无法像常规试图一样移动、缩放或旋转一个SurfaceView。TextureView是Android4.0引入的,除了与SurfaceView一样在单独线程绘制外,还可以像常规视图一样被改变。

 

(2) 使用RenderJavascript
RenderScript是Adnroid3.0引进的用来在Android上写高性能代码的一种语言,语法给予C语言的C99标准,他的结构是独立的,所以不需要为不同的CPU或者GPU定制代码代码。

 

(3) 使用OpenGL绘图
Android支持使用OpenGL API的高性能绘图,这是Android可用的最高级的绘图机制,在游戏类对性能要求较高的应用中得到广泛使用。
Android 4.3最大的改变,就是支持OpenGL ES 3.0。相比2.0,3.0有更多的缓冲区对象、增加了新的着色语言、增加多纹理支持等等,将为Android游戏带来更出色的视觉体验。

 

(4) 尽量为所有分辨率创建资源

减少不必要的硬件缩放,这会降低UI的绘制速度,可借助Android asset studio

 

5、布局调优工具
(1) hierarchy viewer

hierarchy viewer可以方便的查看Activity的布局,各个View的属性、measure、layout、draw的时间,如果耗时较多会用红色标记,否则显示绿色。
hierarchy viewer.bat位于<sdk>/tools/目录下。使用可见:Using Hierarchy Viewer, 示例图如下:


(2) layoutopt
layoutopt是一个可以提供layout及其层级优化提示的命令行,在sdk16以后已经被lint取代,在Windows->Show View->Other->Android->Lint Warnings查看lint优化提示,lint具体介绍可见Improving Your Code with lint





2018-02-10 23:15:00 weixin_33806914 阅读数 15

在 Android 开发的过程中,对性能进行优化是必不可少的一步。而在布局上的优化并不像其他优化方式那么复杂,通过 Android SDK 提供的 Hierarchy Viewer 可以很直接地看到冗余的层级,去除这些多余的层级将使我们的UI变得更加流畅。

如何使用 Hierarchy Viewer ?
  1. 在 Android studio 菜单栏上,点击 Tools --> Android --> Android Device Monitor

  2. 在 Android Device Monitor 菜单栏上,点击 Window --> Open perspective --> Hierarchy Viewer 即可。

然而,一般在真机上无法使用 Hierarchy Viewer,只能在运行开发版 Android 系统的设备进行交互(一般来说,使用模拟器上即可),着实有点遗憾。但是,也可以在真机上通过 root 等一系列操作之后,便可以使用 Hierarchy Viewer 。这部分教程就需要大家在网上另行查阅了。

下面是一些常用的布局优化方式:

一、include 布局

当多个页面公用了一些UI组件时,就可以使用 include 布局。Android 提供了 include 标签,让我们可以将子布局引入到一个布局文件中,这样一来,公用布局就可以独立成为一个布局 xml,其他页面只要 include 引用这个布局xml即可。

下面以一个自定义标题栏为例

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

    <ImageButton
        android:id="@+id/title_back_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:src="@drawable/back" />

    <TextView
        android:id="@+id/title_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Title" />
</RelativeLayout>

将该标题栏引入一个Activity的xml中

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.jerry.myapplication.MainActivity">

    <include
        android:id="@+id/top_title"
        layout="@layout/common_title" />

    <TextView
        android:id="@+id/username_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

通过 include 标签引入 common_title 这个布局(注意:include 布局中指定布局 xml 是使用 layout 属性,而不是 android:layout 属性)。这样一来,就复用了 common_title 的标题栏效果,不必在每个页面中重复定义标题栏布局。大大降低了我们维护 xml 的成本,也提升了代码复用率。

include 标签的原理:

在解析 xml 布局时,如果检测到 include 标签,那么就直接把该布局下的根视图添加到 include 所在的父视图中。对于布局 xml 的解析最终都会调用到 LayoutInflaterinflate 方法,该方法最终又会调用 rInflate 方法。这个方法就是遍历 xml 中的所有元素,然后逐个进行解析。

如何获取 include 布局里的控件?

以上面例子为例,获取标题栏内的 Textview

 private TextView mTextView;

 mTextView = findViewById(R.id.top_title).findViewById(R.id.title_textview);

二、merge 标签

merge 标签适用于子布局的根视图与它的父视图是同一类型。它的作用是合并UI布局,降低UI布局的嵌套层次。使用场景是存在多层使用同一种布局类的嵌套视图,这种情况下用merge标签作为子视图的顶级视图来解决多余的层级。

7182360-96777d78deff4ec7.png

如上图,child_view 与 parent_view 都是FrameLayout类型,那么 child_view 下的两个控件可以直接使用 parent_view 来布局,这样就可以去除 child_view 这个层级。

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

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</FrameLayout>

上面这个布局相当于是 child_view,而 Activity 内容视图的顶层布局也 FrameLayout,因此产生了视图冗余,可以用 merge 标签去掉这层冗余。

下面是screen_title.xml文件的源代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
    <!-- Popout bar for action modes -->
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
        android:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@android:id/title" 
            style="?android:attr/windowTitleStyle"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    <!-以下就是开发人员设置的布局所填充的位置-->
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</merge>

与 include 一样,merge 的解析也在 LayoutInflater 的 inflate() 函数中。在 inflate() 函数中循环解析 xml中 的 tag,如果解析到 merge 标签则会调用 rinflate 函数。

注意事项:
  1. merge 必须作为布局文件的根节点标签。

  2. merge 并不是一个ViewGroup,也不是一个View,它相当于声明了一些视图,等待被添加。

  3. 因为 merge 标签不是 View,所以对 merge 标签设置的所有属性都是无效的。

  4. 因为 merge 标签不是 View,所以在通过 LayoutInflate.inflate 方法渲染的时候,第二个参数必须指定一个父容器,且第三个参数必须为 true,也就是必须为merge下的视图指定一个父亲节点。

  5. 如果 Activity 的布局文件根节点是 FrameLayout,可以替换为 merge 标签,这样,执行 setContentView 之后,会减少一层 FrameLayout 节点。

三、ViewStub 视图

ViewStub 是什么?

ViewStub 是一个不可见的和能在运行期间延迟加载目标视图的、宽高都为0的 View (ViewStub 继承 View)。当对一个 ViewStub 调用 inflate() 方法或设置它可见时,系统会加载在 ViewStub 标签中指定的布局,然后将这个布局的根视图添加到 ViewStub 的父视图中。换句话说,在对 ViewStub 调用 inflate() 方法或者设置 visible 之前,它是不占用布局空间和系统资源的,它只是为目标视图占了一个位置而已。

何时使用 ViewStub?

当我们只需要在某些情况下才加载一些耗资源的布局时,ViewStub 就成为我们实现这个功能的重要手段。

例如:有一个显示九宫格图片的 GridView 视图,我们想根据网络返回的数据来判断是否加载该 GridView ,因为默认加载的话会造成资源浪费,系统加载成本较高。这时使用 ViewStub 标签就可以很方便实现延迟加载。

以下是一个小小的演示,在一个 Activity 中使用 ViewStub 来动态加载
GridView。

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

    <include
        android:id="@+id/top_title"
        layout="@layout/common_title" />

    <Button
        android:id="@+id/show_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示图片" />

    <ViewStub
        android:id="@+id/comment_stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/layout_image_gv" />

</RelativeLayout>

布局的最后使用 ViewStub 来加载 layout_image_gv.xml 布局,下面是 layout_image_gv.xml 的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#aaaaaa">

    <TextView
        android:id="@+id/image_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="显示九宫格GridView" />

    <GridView
        android:id="@+id/image_gc"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/image_desc"
        android:numColumns="3">

    </GridView>
</RelativeLayout>
public class StubLayoutActivity extends AppCompatActivity {

    private ViewStub gvStub;
    private Button mButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_activity_stub);

        gvStub = findViewById(R.id.comment_stub);

        mButton = findViewById(R.id.show_btn);

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //加载目标视图,不能多次调用,否则会引发异常
                gvStub.inflate();
                //gvStub.setVisibility(View.VISIBLE);

            }
        });
    }
}
ViewStub 小结

当用户手动调用 ViewStub 的 inflate 或者 setVisibility 函数(实际上也是调用 inflate 函数)时,会将 ViewStub 自身从父控件中移除,并且加载目标布局,然后将目标布局添加到 ViewStub 的父控件中,这样就完成视图的动态替换,也就是延迟加载功能。

四、减少视图树层级

为什么要减少视图层级?

每一个视图在显示时会经历测量、布局、绘制的过程,如果我们的布局中嵌套的视图层次过多,就会造成额外测量、布局等工作,使得UI变得卡顿,影响用户的使用体验。

例如一个简单的列表 Item

<?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="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

而使用 RelativeLayout 来布局这个 item view 就可以减少一层 LinearLayout 的渲染。

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

    <ImageView
        android:id="@+id/profile_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/name_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/profile_image" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/profile_image" />
</RelativeLayout>

五、总结

在Android UI布局过程中,需要遵守的原则有以下几点:

  1. 尽量多使用 RelativeLayout ,不要使用绝对布局 AbsoluteLayout;

  2. 在 ListView 等列表组件中尽量避免使用 LinearLayout 的 layout_weight 属性(子视图使用了 layout_weight 属性的 LinearLayout 会对它的子视图进行两次测量。)

  3. 将可复用的组件抽取出来并通过 <include/> 标签使用;

  4. 使用 <ViewStub/> 标签来加载一些不常用的布局;

  5. 使用 <merge/> 标签来减少布局的嵌套层次。

Android 性能优化之布局优化

阅读数 2

一、思路布局优化的思路简单来说就是尽量减少布局文件的层级,层级减少了也就意味着Android绘制时的工作量少了,那么程序的性能自然也就提高了。二、优化策略2.1选择性能较高的ViewGroupRelativeLayout和LinearLayout同时存在的话,优先选择LinearLayout,因为RelativeLayou...

博文 来自: weixin_34311757

Android 性能优化之布局优化

阅读数 215

在布局优化中,Androi的官方提到了这三种布局、、1.重用布局include  include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,这在布局编写方便提供了大大的便利。例如,每个activity都会用到的titlebar.xml

博文 来自: sergeycao

Android 性能优化之布局优化

阅读数 51

Android性能优化之布局1.避免过度OverDrawOverdraw就是过度绘制,是指在一帧的时间内(16.67ms)像素被绘制了多次,理论上一个像素每次只绘制一次是最优的,但是由于重叠的布局导致一些像素会被多次绘制,而每次绘制都会对应到CPU的一组绘图命令和GPU的一些操作,当这个操作耗时超过16.67ms时,就会出现掉帧现象,也就是我们所说的卡顿,所以对重叠不可见元素的重复绘制

博文 来自: zhaostrong

Android 性能优化 - 布局优化

阅读数 631

1.合理选择ViewGroup在选择使用Android中的布局方式的时候应该遵循:尽量少使用性能比较低的容器控件,比如RelativeLayout,但如果使用RelativeLayout可以降低布局的层次的时候可以考虑使用。Android中的控件是树状的,降低树的高度可以提升布局性能。RelativeLayout的布局比FrameLayout、LinearLayout等简...

博文 来自: github_35186068

android 性能优化之布局优化

阅读数 2

注:本文内容是《Android群英传》学习笔记,主要提炼书中内容然后加上部分自己的完善和补充。android渲染机制16ms:1000ms在显示60帧画面的单位时间。系统通过VSYNC信号出发对UI的渲染、重绘。检测UI渲染时间工具开发者选项-&gt;ProfileGPURendering(GPU配置未见)-&gt;Onthe...

博文 来自: weixin_33825683
没有更多推荐了,返回首页