熊猫儿
发表于 2016-9-22 15:51
Android官方开发文档Training系列课程中文版:布局性能优化之布局复用
标签: android性能优化布局布局优化布局复用
2016-09-13 13:30 266人阅读 评论(0) 收藏 举报
http://static.blog.csdn.net/images/category_icon.jpg 分类:
翻译(103) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg
目录(?)[+]
原文地址:http://android.xsoftlab.net/training/improving-layouts/reusing-layouts.html尽管Android提供了种类繁多的常用控件,但是有时你可能希望重用一些比较复杂的布局。如果要重用这些布局,可以使用< include/>标签与< merge/>标签,它们可将一个布局嵌入进另一个布局中。可重用布局这项功能特别强大,它可以使你创建那些复杂的可重用布局。比方说,可以用来创建一个含有yes和no按钮的容器或者一个含有progressBar及一个文本框的容器。它还意味着程序可以对这些布局进行单独控制。所以,虽然说你可以通过自定义View的方式来实现更为复杂的UI组件,但是重用布局的方法更简便一些。创建一个可重用的布局如果你已经知道哪一个布局需要重用,那么就创建一个新的xml文件用来定义这个布局。下面就定义了一个ActionBar的布局文件,众所周知,ActionBar是会在每个Activity中统一出现的:<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width=”match_parent” android:layout_height="wrap_content" android:background="@color/titlebar_bg"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/gafricalogo" /></FrameLayout>
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
使用< include/>标签在希望添加重用布局的布局内,添加< include/>标签。下面的例子就是将上面的布局加入到了当前的布局中:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width=”match_parent” android:layout_height=”match_parent” android:background="@color/app_bg" android:gravity="center_horizontal"> <include layout="@layout/titlebar"/> <TextView android:layout_width=”match_parent” android:layout_height="wrap_content" android:text="@string/hello" android:padding="10dp" /> ...</LinearLayout>
熊猫儿
发表于 2016-9-22 15:53
你也可以重写布局的参数,但只仅限于以android:layout_*开头的布局参数。就像下面这样:<include android:id=”@+id/news_title” android:layout_width=”match_parent” android:layout_height=”match_parent” layout=”@layout/title”/>
[*]1
[*]2
[*]3
[*]4
[*]1
[*]2
[*]3
[*]4
如果你要重写< include>标签指定布局的布局属性,那么必须重写android:layout_height及android:layout_width这两个属性,以便使其它属性的作用生效。使用< merge>标签在将一个布局内嵌进另一个布局时,< merge>标签可以帮助消除冗余的View容器。举个例子,如果你的主布局是一个垂直的LinearLayout,在它的内部含有两个View,并且这两个View需要在多个布局中重用,那么重用这两个View的布局需要有一个root View。然而,使用单独的LinearLayout作为这个root View会导致在一个垂直的LinearLayout中又嵌了一个垂直的LinearLayout。其实这个内嵌的LinearLayout并不是我们真正想要的,此外它还会降低UI性能。为了避免出现这种冗杂的View容器,你可以使用< merge>标签作为这两个View的root View:<merge xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/add"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/delete"/></merge>
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
那么现在再使用这个布局的时候,系统会自动忽略< merge>标签,并会将两个Button View直接加入到布局< include/>标签所指定的位置
熊猫儿
发表于 2016-9-22 15:54
Android官方开发文档Training系列课程中文版:布局性能优化之布局层级优化
标签: android性能优化布局优化布局性能优化
2016-09-12 11:29 292人阅读 评论(0) 收藏 举报
http://static.blog.csdn.net/images/category_icon.jpg 分类:
翻译(103) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg
目录(?)[+]
原文地址:http://android.xsoftlab.net/training/improving-layouts/index.html引言布局是直接影响用户体验的关键部分。如果实现的不好,那么布局很有可能会导致内存的紧张。Android的SDK包含的一些工具可以用来检查布局性能上的问题。结合本章的课程学习,你将有能力以低成本的内存开销实现更为顺畅的UI体验。优化布局层级有一个常见的误解就是使用基本的布局结构会使布局更高效。然而却不是这样的,每一个控件、布局容器都需要执行初始化、排布、绘制等过程。举个例子,使用内嵌的LinearLayout会使布局层级过度加深。进一步讲,内嵌多个使用了layout_weight参数的控件所花费的代价尤其高昂,因为每个子View都需要被测量两次。这在布局被重复加载时尤为重要,比如使用在ListView或GridView中的时候。在这节课我们将会学习如何使用Hierarchy Viewer工具及Layoutopt工具来检查、优化布局。布局检查Android的SDK包含了一个名为Hierarchy Viewer的工具。使用该工具可以帮助发现影响布局性能的瓶颈。Hierarchy Viewer工作于所选择的进程上,它会显示一个布局树。每个View节点上的信号灯代表了该View在测量、排布、绘制上的性能优劣,这可以帮助你发现潜在的问题。举个例子说明:下图是ListView的一个Item。该Item左边用于显示图片,而右边则显示两行文本。因为该Item会被进行多次加载,所以对其优化的话,那么UI性能会有显著的提升。http://android.xsoftlab.net/images/training/layout-listitem.pngHierarchy Viewer工具位于< sdk>/tools/目录下。打开后,Hierarchy Viewer会列出当前的可用设备以及设备上运行的组件。点击Load View Hierarchy来浏览所选组件的布局层级。下图是上图位于ListView中的运行效果演示:http://android.xsoftlab.net/images/training/hierarchy-linearlayout.png
熊猫儿
发表于 2016-9-23 14:25
在上图中,我们可以看到View的层级为3,并且在文本的排布上发现了一些问题。点击每个节点我们可以看到每个阶段所花费的时间(如下图所示)。那么我们就可以很清晰的知道哪个Item在测量、排布、渲染上花费的时间最长,所以我们就需要花点时间专门对其优化。http://android.xsoftlab.net/images/training/hierarchy-layouttimes.png这里我们可以看到每个阶段所花费的时间:
[*]Measure: 0.977ms
[*]Layout: 0.167ms
[*]Draw: 2.717ms
调整布局因为上面的示例说布局的性能慢是由于内嵌了一个LinearLayout,所以改进这部分性能只能通过扁平化来处理。要尽量使布局变浅变宽,杜绝变窄变深。RelativeLayout可以实现这样的布局。所以当使用RelativeLayout实现这样的布局时,那么可以看到布局的层级变为了2。我们所看到的布局图就是这个样子:http://android.xsoftlab.net/images/training/hierarchy-relativelayout.png下面是优化后的时间开销:
[*]Measure: 0.598ms
[*]Layout: 0.110ms
[*]Draw: 2.146ms
我们可能会看到很微小的改进。在改进时间上的大部分差别是由于LinearLayout的权重造成的,它会降低测量的速度。这里的示例仅仅是个优化手段的演示,在开发过程中应当认真考虑是否有必要使用权重。
熊猫儿
发表于 2016-9-23 14:26
使用Lint开发者应该使用lint工具来检查布局层级是否有可优化的地方。Lint 与Layoutopt 相比有更加强大的功能。一些Lint的检查规则如下:
[*]使用组合图形 - 一个包含了ImageView和TextView的LinearLayout作为组合图形处理起来更加高效。
[*]合并根帧布局 - 如果一个FrameLayout是根布局,并且它没有提供背景色或内边距什么的,那么可以使用合并标签将其替换,这可以稍微的改进性能。
[*]无用的叶子节点 - 如果一个布局没有子View,没有背景色,那么通常可以将其移除。
[*]无用的中间节点 - 如果一个布局内部只含有一个子View,并且不是ScrollView或者根布局,也没有背景色,那么可以将它移除,并将其子View移动到它的父容器内。
[*]非常深的布局嵌套 - 一个被嵌套很深的布局通常不利于性能。考虑使用RelativeLayout或者GridLayout这种扁平化布局来改进性能。默认的最大深度为10。
Lint的另一个好处就是它被集成进了Android Studio。Lint会在程序编译时自动运行。你也可以管理检查Lint的配置,在Android Studio内通过File>Settings>Project Settings路径可以找到。http://android.xsoftlab.net/images/tools/studio-inspections-config.pngLint可以自动的修复一些问题,并且会对余下的问题提供一些优化建议,以便使开发者手动修复。
熊猫儿
发表于 2016-9-23 14:28
Android官方开发文档Training系列课程中文版:性能优化建议
标签: android性能优化文档性能优化提示
2016-09-06 08:55 1356人阅读 评论(0) 收藏 举报
http://static.blog.csdn.net/images/category_icon.jpg 分类:
翻译(103) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg
目录(?)[+]
原文地址:http://android.xsoftlab.net/training/articles/perf-tips.html本篇文章主要介绍那些可以提升整体性能的微小优化点。它与那些能突然改观性能效果的优化手段并不属于同一类。选择正确的算法与数据结构必然是我们的第一总则,但是这不是我们这篇文章要介绍的。你应该将这篇文章所提及的知识点作为编码的日常习惯,这可以提升常规代码的执行效率。下面是书写代码的基本准则:
[*]绝不要做你不需要的工作。
[*]如果可以不申请内存就不要申请,要合理复用已有的对象。
另一个较复杂的问题就是被优化过的APP肯定是要运行在各种类型的硬件平台上。不同版本的虚拟机运行在不同的处理器上肯定会有不同的运行速度。需要特别说明的是,在模拟器上测试很少会得知其它设备的性能。在不同设备上还有一个很大的不同点就是有没有JIT(JIT的意思是即时编译器):在JIT设备上运行的最优代码并不总在没有JIT设备上有效。为了确保APP可以在各类设备上运行良好,要确保代码在各个版本的平台上都是高效的。避免创建不必要的对象创建对象绝不是没有成本的。虽然分代垃圾收集器可以使临时对象的分配成本变得很低,但是内存分配的成本总是远高于非内存分配的成本。随着更多对象的生成,你可能就开始关注垃圾收集器了。虽然Android 2.3中出现的并发收集器可能会帮到你,但是不必要的工作总是应该避免的。因此,要避免创建不需要的对象。下面的示例可能会帮到你:
[*]如果你有个返回字符串的方法,该方法所返回的字符串总是被接在一个StringBuffer对象后面。那么就可以更改此方法的实现方式:让该字符串直接跟在StringBuffer的后面返回。这样就可以避免创建那些临时性的变量。
[*]当从字符串中提取子串时,应该尝试返回原始数据的子串,而不是创建一个副本。子串将会创建一个新的String对象,但是它与char[]共用的是同一数据。采用这种方式的唯一不足就是:虽然使用了其中的一部分数据,但是剩余的数据还都保留在内存中。
一条更为先进的法则就是,将多维数组转换为平行数组使用:
[*]int数组的效率要比Integer数组的效率高的多。
[*]如果你需要实现一个用于存储(Foo,Bar)对象的数组,要记得使用两个平行的Foo[],Bar[]数组,这要比单一的(Foo,Bar)数组效率好太多。
通常来说,要尽量避免创建那些生命周期很短的临时变量。更少的对象创建意味着更低频率的垃圾回收,这会直接反应到用户体验上。首选静态如果不需要访问对象的属性,那么就可以将方法设置为静态方法。这样调用将会增加15%-20%的速度。这还是一个好的习惯,因为这样可以告诉其它方法一个信号:它们更改不了对象的状态。
熊猫儿
发表于 2016-9-23 14:32
使用常量请先考虑以下声明:static int intVal = 42;static String strVal = "Hello, world!";
[*]1
[*]2
[*]1
[*]2
编译器会产生出一个类的实例化方法,名为< clinit>,它会在类首次被用到的时候执行。该方法会将值42存到intVal中,并将字符串常量表中的引用赋给strVal。当这些值被引用之后,其它属性才可以访问它们。我们可以使用”final”关键字来改进一下:static final int intVal = 42;static final String strVal = "Hello, world!";
[*]1
[*]2
[*]1
[*]2
这样的话,类就不需要再调用< clinit>方法,因为常量的初始化工作被移入了dex文件中。代码可以直接引用intVal为42的值,并且访问strVal也会直接得到字符串”string constant” ,这样可以省去了查找字符串的过程。Note: 这样优化手段仅仅适用于基本数据类型以及字符串常量,不要作用其它类型。避免内部的get\set方法像C++这种本地语言通常都会使用get方法来访问属性。这对C++来说是一个非常好的习惯,并且C#、Java等面向对象语言也广泛使用这种方式,因为编译器通常会进行内联访问,并且如果你需要限制访问或者调试属性的话,只需要添加代码就可以。不过,这在Android上并不是个好习惯。方法调用的开销是非常大的。虽然为了遵循面向对象语言提供get、set方法是合理的,但是在Android中最好是可以直接访问对象的字段。在没有JIT的设备中,直接访问对象字段的速度要比通过get方法访问的速度快3倍。在含有JIT的设备中,这个效率会达到7倍之多。注意:如果你使用了ProGuard,那么就有了一个两全其美的结果,因为ProGuard会直接为你进行内联访问。使用增强for循环增强for循环可用于实现了Iterable接口的集合或数组。在集合内部,迭代器需要实现接口方法:hasNext()以及next()。
熊猫儿
发表于 2016-9-23 14:34
有以下几种访问数组的方式:static class Foo { int mSplat;}Foo[] mArray = ...public void zero() { int sum = 0; for (int i = 0; i < mArray.length; ++i) { sum += mArray.mSplat; }}public void one() { int sum = 0; Foo[] localArray = mArray; int len = localArray.length; for (int i = 0; i < len; ++i) { sum += localArray.mSplat; }}public void two() { int sum = 0; for (Foo a : mArray) { sum += a.mSplat; }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
zero()方法是最慢的,因为JIT不能够对每次访问数组长度的开销进行优化。one()方法是稍快点的。它将一切元素放入了本地变量,这样避免了每一次的查询。只有数组的长度提供了明显的性能提升。two()方法是最快的。它使用了增强for循环。所以应当在默认情况下使用增强for循环。Tip: 也可以查看Josh Bloch 的 Effective Java,第46条。考虑使用包内访问请先思考以下类定义:public class Foo { private class Inner { void stuff() { Foo.this.doStuff(Foo.this.mValue); } } private int mValue; public void run() { Inner in = new Inner(); mValue = 27; in.stuff(); } private void doStuff(int value) { System.out.println("Value is " + value); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
http://static.blog.csdn.net/images/save_snippets.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
上面的代码定义了一个内部类,它可以直接访问外部类的私有成员以及私有方法。这是正确的,这段代码将会打印出我们所期望的”Value is 27”。这里的问题是:VM会认为Foo$Inner直接访问Foo对象的私有成员是非法的,因为Foo和Foo$Inner是两个不同的类,虽然Java语言允许内部类可以直接访问外部类的私有成员(PS:虚拟机与语言是两种互不干扰的存在)。为了弥补这种差异,编译器专门为此生成了一组方法:/*package*/ static int Foo.access$100(Foo foo) { return foo.mValue;}/*package*/ static void Foo.access$200(Foo foo, int value) { foo.doStuff(value);}
熊猫儿
发表于 2016-9-24 21:47
当内部类代码需要访问属性mValue或者调用doStuff()方法时会调用上面这些静态方法。上面的代码归结为你所访问的成员属性都是通过访问器方法访问的。早期我们说通过访问器访问要比直接访问慢很多,所以这是一段特定语言形成的隐性性能开销示例。避免使用浮点型一般来说,在Android设备上浮点型要比整型慢大概2倍的速度。在速度方面,float与double并没有什么区别。在空间方面,double是float的两倍大。所以在桌面级设备上,假设空间不是问题,那么我们应当首选double,而不是float。还有,在对待整型方面,某些处理器擅长乘法,不擅长除法。在这种情况下,整型的除法与取模运算都是在软件中进行的,如果你正在设计一个哈希表或者做其它大量的数学运算的话,这些东西应该考虑到。使用本地方法要当心使用本地代码开发的APP并不一定比Java语言编写的APP高效多少。首先,它会花费在Java-本地代码的转换过程中,并且JIT也不能优化到这些边界。如果你正在申请本地资源,那么对于这些资源的收集能明显的感觉到困难。除此之外,你还需要对每一种CPU架构进行单独编译。你可能甚至还需要为同一个CPU架构编译多个不同的版本:为G1的ARM处理器编译的代码不能运行在Nexus One的ARM处理上,为Nexus One的ARM处理器编译的代码也同样不能运行在G1的ARM处理器上。本地代码在这种情况下适宜采用:当你有一个已经存在的本地代码库,你希望将它移植到Android上时,不要为了改善Java语言所编写的代码速度而去使用本地代码。如果你需要使用本地代码,那么应该读一读JNI Tips.Tip: 相关信息也可以查看Josh Bloch 的 Effective Java,第54条。性能误区在没有JIT的设备中,通过具体类型的变量调用方法要比抽象接口的调用要高效,这是事实。举个例子,通过HashMap map调用方法要比Map map调用方法要高效的多,开销也少,虽然这两个实现都是HashMap。事实上速度并不会慢2倍这么多;真实的不同大概有6%的减缓。进一步讲,JIT会使两者的差别进一步缩小。在没有JIT的设备上,通过缓存访问属性要比反复访问属性要快将近20%的速度。在JIT的设备中,属性访问的花销与本地访问的花销基本一致,所以这不是一项有多少价值的优化手段,除非你觉得这样做的话代码更易读(这对static,final,常量同样适用)。
熊猫儿
发表于 2016-9-24 21:48
经常估测在开始优化之前,要确保你有个问题需要解决:要确保你可以精准测量现有的性能,否则将不能观察到优化所带来的提升。基准点由Caliper的微型基准点框架创建。基准点很难正确获得,所以Caliper将这份很难处理的工作做了,甚至是在你没有在测量那些你想测量的地方的时候它也在工作。我们强烈的推荐你使用Caliper来创建自己的微型基准点。你可能还发现Traceview非常有助于提升性能,不过你应该意识到Traceview工作的时候JIT并没有开启。这会错误的认为JIT会将损失掉的时间弥补回来。这尤其重要:根据Traceview所更改的结果会使实际代码运行的更快。有关更多提升APP性能的工具及方法,请参见以下文档:
[*]Profiling with Traceview and dmtracedump
[*]Analyzing UI Performance with Systrace
Android官方开发文档Training系列课程中文版:APP的内存管理
标签: android操作系统内存管理文档app
2016-09-05 08:58 16251人阅读 评论(5) 收藏 举报
http://static.blog.csdn.net/images/category_icon.jpg 分类:
翻译(103) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg
目录(?)[+]
写在开头的话: 如果有同学对Android性能比较关注的,可以阅读这篇文章:Android性能优化建议原文地址:http://android.xsoftlab.net/training/articles/memory.html随机存储器(RAM)在任何运行环境中都是一块非常重要的区域,尤其是在内存受限的移动操作系统上。尽管Android的Dalvik虚拟机会对其进行垃圾回收,但是这不意味着APP就可以忽略申请及释放的内存。为了可以使垃圾回收器能够有效清理APP所占用的内存空间,你需要防止内存泄漏发生,并需要在适当的时间将Reference对象释放。对大多数APP来说,垃圾回收器会在正确的对象使用完毕之后将其所占用的内存回收释放。这节课将会学习Android如何管理APP进程以及内存空间、以及如何减少内存的占用。Android如何管理内存Android并没有提供专门的内存交换空间,但是它使用了paging及memory-mapping来管理内存。这意味着任何你所修改的内存——无论是否被对象分配所使用,或者是被内存映射所占用——它们会一直遗留在内存中,不能被交换出去。所以完全释放APP内存的唯一方式就是释放任何你可能所持有的对象引用,这样才可以使垃圾回收器对其进行回收。不过这里有一个例外:任何没有被修改的文件映射,比如代码,在系统需要的时候会被移出RAM。共享内存为了可以在RAM中满足一切要求,Android试着在进程间共享RAM页面。它通过以下几种方式实现:
[*]每个APP进程都是由一个名为Zygote的进程fork出来的。Zygote进程在系统启动加载通用框架代码及资源(比如Activity的主题)时启动。为了启动新的APP进程,系统会先fork出Zygote进程,然后再在新的进程中加载、运行APP的代码。这使得为Android框架代码以及资源所分配的RAM页面在APP进程间共享成为了可能。
[*]大多数的静态数据都是被映射到进程中的。这种方式不仅可以在进程间共享数据,还可以在需要的时候将其移除页面。静态数据包含:Dalvik代码(放置在预链接的.odex文件中),APP资源以及在.so文件中的本地代码。
[*]在很多地方,Android通过显式内存分配区域在不同的进程间共享同一块RAM。比如,WindowSurface就在APP与屏幕合成器间使用了共享内存,CursorBuffer在内容提供者与客户端之间也使用了共享内存。
由于大量使用了共享内存,所以检查APP占用的内存空间就显得很有必要了。