Android 优化布局层次结构
最后更新于:2022-04-01 20:40:59
前面介绍过使用HierarchyViewer和Android lint来优化我们的程序,这一篇算是总结性的,借助一个小例子来说用怎么优化应用布局。这个例子是android官网给出的,作者也当一把翻译。
多数开发者可能会这样认为,使用基本的布局结构会产生高效的布局性能,其实这个想法是不完全正确的。我们每一个添加到应用的控件和布局,都需要初始化、布局、绘制,这些多是需要时间降低显示速度的。另外,嵌套多个使用layout_weight属性的LinearLayout实例会花费更大的代价,因为每一个子布局都要测量两次。如果这种布局使用在ListView或者GridView中,渲染时会更耗时。
下面,我们根据一个布局示例使用HierarchyViewer和Android lint来检测优化布局结构。
## 使用HierchyViewer
HierchyViewer需要你选择一个已连接的设备或者模拟器中的一个运行的程序,显示出布局的树结构。每个块上的红绿灯代表它的测量,布局,以及绘图性能,帮助你找出潜在的问题。有读者在读完[《Android UI 优化——使用HierarchyViewer工具》](http://blog.csdn.net/xyz_lmn/article/details/14222975)后提出HierarchyViewer没有显示出红绿黄灯和时间,这怎么解决。在tool目录启动HierarchyViewer确实没有相应的设置去显示,但是可以在eclipse中启动HierarchyViewer去设置。Window->Open Perspective->others->hierarchyviewer。在Tree View点击三个圆圈的按钮,如图一:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c09ca04.jpg)
图一
图一图二给出了显示绘制时间和不显示绘制时间的区别:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c0b7031.jpg)
图二
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c0d854c.jpg)
图三
我们开始分析一个ListView的item布局,如图四,这个布局的左边显示了一幅图片,两个文字item放在右边。当布局被重复加载的时优化显得尤为重要。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c0eee9f.jpg)
图四
图四的布局文件在HierarcheyViewer中显示的层次结构如图五,选中LinearLayout会显示各种性能参数,如图六:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c10b9e9.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c12eeb5.jpg)
图五 图六
在图五中显示视图有三层结构,并且有些显示了红灯黄灯,这就需要我们优化,图六中也显示了绘制时间。
上述布局性能较低的原因主要是由一个内嵌的LinearLayout所引起,为了提高性能,我们使用RelativeLayout,将该布局浅而广的扁平化结构代替为深而窄的树形结构,这样该布局变为一个2层的结构,修改后的布局结构如图七:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c141c12.jpg)
图七
此时,绘制时间减少了,并且去掉了红灯、黄灯显示。
## 使用lint
[《Android代码优化——使用Android lint工具》](http://blog.csdn.net/xyz_lmn/article/details/14222939)简单说明了lint的使用,在布局文件内运行Lint工具,可以找出那些可能要优化的布局结构。Lint工具代替Layoutopt工具,并且有更大的功能。如下是Lint的一些示例:
1、Use compound drawables,在LineraLayout布局中包含一个ImageView和一个TextView,可以使用compound drawable代替,性能会更好。
2、Merge root frame,如果root布局是FrameLayout,可以使用代替,具体可参考[《Android抽象布局——include、merge 、ViewStub》](http://blog.csdn.net/xyz_lmn/article/details/14524567)。
3、Useless leaf,没有子布局的layout可以去掉
4、Useless parent ,一个布局不是ScrollView或者不是一个根布局,也没有背景,只有一个孩子节点,可以被删掉。
5、Deep layouts,布局若有太多内嵌,则性能很差。考虑使用RelativeLayout 以及GridLayout等扁平化布局代替。默认布局最大深度是10.
Android使用Lint请移步至[《Android代码优化——使用Android lint工具》](http://blog.csdn.net/xyz_lmn/article/details/14222939)。
';
Android抽象布局——include、merge 、ViewStub
最后更新于:2022-04-01 20:40:56
在布局优化中,Androi的官方提到了这三种布局、、,并介绍了这三种布局各有的优势,下面也是简单说一下他们的优势,以及怎么使用,记下来权当做笔记。
## 1、布局重用
标签能够重用布局文件,简单的使用如下:
~~~
...
~~~
1)标签可以使用单独的layout属性,这个也是必须使用的。
2)可以使用其他属性。标签若指定了ID属性,而你的layout也定义了ID,则你的layout的ID会被覆盖,[解决方案](http://my.eoe.cn/814017/archive/3415.html)。
3)在include标签中所有的android:layout_*都是有效的,前提是必须要写layout_width和layout_height两个属性。
4)布局中可以包含两个相同的include标签,引用时可以使用如下方法解决([参考](http://www.coboltforge.com/2012/05/tech-stuff-layout/)):
~~~
View bookmarks_container_2 = findViewById(R.id.bookmarks_favourite);
bookmarks_container_2.findViewById(R.id.bookmarks_list);
~~~
## 2、减少视图层级
标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。多用于替换FrameLayout或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用标签优化。
~~~
~~~
现在,当你添加该布局文件时(使用标签),系统忽略节点并且直接添加两个Button。更多介绍可以参考《[Android Layout Tricks #3: Optimize by merging](http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-by.html)》
## 3、需要时使用
标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。是一个不可见的,大小为0的View。标签使用如下:
~~~
~~~
当你想加载布局时,可以使用下面其中一种方法:
~~~
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
~~~
当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。
注:ViewStub目前有个缺陷就是还不支持 标签。
更多标签介绍可以参考《[Android Layout Tricks #3: Optimize with stubs](http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-with.html)》
';
Android UI 优化——使用HierarchyViewer工具
最后更新于:2022-04-01 20:40:54
进入正题,我们这一篇文章会提到为什么使用HierarchyViewer,怎么使用HierarchyViewer,后者内容会多一下。
## 为什么使用HierarchyViewer
不合理的布局会使我们的应用程序UI性能变慢,HierarchyViewer能够可视化的角度直观地获得UI布局设计结构和各种属性的信息,帮助我们优化布局设计。HierarchyViewer是我们优化程序的工具之一,它是Android自带的非常有用的工具,可以帮助我们更好地检视和设计用户界面(UI),绝对是UI检视的利器。
## 怎么使用HierarchyViewer
Hierarchy Viewer是随Android SDK发布的工具,位于Android SDK/tools/hierarchyviewer.bat (Windows操作系统,mac上显示的为hierarchyviewer),使用起来也是超级简单,通过此工具可以详细的理解当前界面的控件布局以及某个控件的属性(name、id、height等)。
1)连接设备真机或者模拟器(真机可能无法连接,我用的2.3,连接上了,没读到内容);
2)启动你要观察的应用。
3)打开Hierarchyviewer,点击hierarchyviewer文件即可。连接后如下图,这个图是在官方文档获取的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bfccd4e.jpg)
4)双击最上面的,如下图的,这个是当前窗口,加载完毕后会显示当前界面层次结构。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bfea8c7.jpg)
5)观察层次结构图,这个图有点大,可以拖动。View Hierarchy窗口显示了Activity的所有View对象,选中某个View还可以查看View的具体信息,最好选择工具中的Show Extras选项。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c015df7.jpg)
6)观察单个view,选择单个view后会出现如下图所示图形。这里会看到Measure、Layout、Draw的耗时。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392c0551aa.jpg)
View Hierarcy 同时能帮助你识别渲染性能比较低的部分。View节点中带有红色或黄色的点代表速度较慢的View对象。如单步运行应用程序那样,你可以这样来判断某个View 速度一直很慢,还是只在某个特定环境下速度才慢。
请注意,低性能并不表示一定有问题,特别像是ViewGroup对象,View的子节点越多,结构越复杂,性能越差。
View Hierarchy 窗口还可以帮助你找到性能问题。只要看每个View节点的性能指标(颜色点)就可以,你可以看到测量(布局或绘制)最慢的View对象是哪个,这样你就能快速确定,要优先察看哪个问题。
';
Android代码优化——使用Android lint工具
最后更新于:2022-04-01 20:40:52
作为移动应用开发者,我们总希望发布的apk文件越小越好,不希望资源文件没有用到的图片资源也被打包进apk,不希望应用中使用了高于minSdk的api,也不希望AndroidManifest文件存在异常,lint就能解决我们的这些问题。Android lint是在ADT 16提供的新工具,它是一个代码扫描工具,能够帮助我们识别代码结构存在的问题,主要包括:
1)布局性能(以前是 layoutopt工具,可以解决无用布局、嵌套太多、布局太多)
2)未使用到资源
3)不一致的数组大小
4)国际化问题(硬编码)
5)图标的问题(重复的图标,错误的大小)
6)可用性问题(如不指定的文本字段的输入型)
7)manifest文件的错误
Android lint可以解决如上的问题,当然还有更多,具体的可以参考[Android Lint Checks](http://tools.android.com/tips/lint-checks)。Android官方也总结了lint能解决的问题,如下图。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bf05aec.jpg)
lint是命令工具,它已经完美的集成到了Eclipse中,我们可以方便的使用。通过lint,我们可以检测出每个问题的说明和问题的严重性,根据检测报告可以对程序作出改进。下面介绍下在Eclipse怎么使用lint。
lint的使用可以通过两个途径,Eclipse左上角的打钩的按钮或者选择项目->右键->Android Tools,如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bf1ee8d.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bf302dc.jpg)
图一 图二
lint工具简单实用,自动化分析,分析完成会给我们分析报告:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bf483ac.jpg)
分析包括中会包括错误和警告,会给出具体的描述、类别、位置。上图是一个错误的描述,下图给出警告描述。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bfa2661.jpg)
Android lint是对android开发者很有帮助的一款工具,对于项目打包发布前优化代码、查找没用到的资源、查找错误等非常有帮助。作为开发者是必须掌握的工具之一,如果想了解更多可以参考[lint](http://developer.android.com/tools/help/lint.html)。
/**
* @author 张兴业
* http://blog.csdn.net/xyz_lmn
* iOS入门群:83702688
* android开发进阶群:241395671
* 我的新浪微博:**[@张兴业TBOW](http://weibo.com/xyzlmn)**
*/
参考:
[http://tools.android.com/tips/lint](http://tools.android.com/tips/lint)
http://tools.android.com/tips/lint-checks
[http://developer.android.com/tools/help/lint.html](http://developer.android.com/tools/help/lint.html)
http://developer.android.com/tools/debugging/improving-w-lint.html
';
Android应用性能优化
最后更新于:2022-04-01 20:40:50
## 遇到的问题:
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
代码优化工具:Lint
内存、方法优化工具:Heap、TraceView
Dalvik日志分析,logcat日志分析
Android手机开发者选项的“过度绘制”选项。
';
避免Android内存泄露
最后更新于:2022-04-01 20:40:47
Android的应用被限制为最多占用16m的内存,至少在T-Mobile G1上是这样的(当然现在已经有几百兆的内存可以用了——译者注)。它包括电话本身占用的和开发者可以使用的两部分。即使你没有占用全部内存的打算,你也应该尽量少的使用内存,以免别的应用在运行的时候关闭你的应用。Android能在内存中保持的应用越多,用户在切换应用的时候就越快。作为我的一项工作,我仔细研究了Android应用的内存泄露问题,大多数情况下它们是由同一个错误引起的,那就是对一个上下文([Context](http://code.google.com/android/reference/android/content/Context.html))保持了长时间的引用。
在Android中,上下文(Context)被用作很多操作中,但是大部分是载入和访问资源。这就是所有的widget都会在它们的构造函数中接受一个上下文(Context)参数。在一个合格的Android应用中,你通常能够用到两种上下文(Context):活动([Activity](http://code.google.com/android/reference/android/app/Activity.html))和应用([Application](http://code.google.com/android/reference/android/app/Application.html))。活动(Activity)通常被传递给需要上下文(Context)参数的类或者方法:
~~~
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}
~~~
这就意味着那个View有一个对整个活动(Activity)的引用并且对这个活动(Activity)中保持的所有对象有保持了引用;通常它们包括整个View的层次和它的所有资源。因此,如果你“泄露”了上下文(Context)(这里“泄露”的意思是你保持了一个引用并且组织GC收集它),你将造成大量的内存泄露。如果你不够小心的话,“泄露”一整个活动(Activity)是件非常简单的事情。
当屏幕的方向改变时系统会默认的销毁当前的活动(Activity)并且创建一个新的并且保持了它的状态。这样的结果就是Android会从资源中重新载入应用的UI。现在想象一下,你写了一个应用,有一个非常大的位图,并且你并不想在每次旋转时都重新载入。保留它并且每次旋转不重新加载的最简单的办法就是把它保存在一个静态字段上:
~~~
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
~~~
这段代码非常快,同时也错的够离谱。它泄露了当第一次屏幕角度改变时创建的第一个活动(Activity)。当一个Drawable被附加到一个View,这个View被设置为drawable的一个回调。在上面的代码片断中,这意味着这个Drawable对TextView有一个引用,同时这个TextView对Activity(Context对象)保持着引用,同时这个Activity对很多对象又有引用(这个多少还要看你的代码了)。
这个例子是造成Context泄露的最简单的一个原因,你可以看一下我们在[主屏幕源码](http://android.git.kernel.org/?p=platform/packages/apps/Launcher.git;a=blob;f=src/com/android/launcher/LauncherModel.java;h=0ef2a806b767142b28b2ff3b37f21f4ca16c355d;hb=cupcake)(查看unbindDrawables()方法)中是通过在Activity销毁时设置保存过的Drawable的回调为空来解决这个问题的。更为有趣的是,你可以创建一个context泄露的链,当然这非常的糟糕。它们可以让你飞快的用光所有的内存。
有两种简单的方法可以避免与context相关的内存泄露。最明显的一个就是避免在context的自身的范围外使用它。上面的例子展示了在类内部的一个静态的引用和它们对外部类的间接引用是非常危险的。第二个解决方案就是使用Application Context。这个context会伴随你的应用而存在,并且不依赖Activity的的生命周期。如果你计划保持一个需要context的长生命周期的对象,请记得考虑Application对象。你可以非常方便的通过调用Context.getApplicationContext() 或者 Activity.getApplication()获取它。
总之,为了避免涉及到context的内存泄露,请记住如下几点:
1. 不要对一个Activity Context保持长生命周期的引用(一个对Activity的引用应该与Activity自身的生命周期相同)
2. 尝试使用应用上下文(context-application)代替活动上下文(context-activity)
3. 如果你不能控制它们的生命周期,在活动(Activity)中避免使用不是静态的内部类,使用静态类并且使用弱引用到活动(Activity)的内部。对于这个问题的解决方法是使用静态的内部类与一个弱引用(WeakReference)的外部类。就像ViewRoot和它的W内部类那么实现的。
4. 垃圾回收器对于内存泄露来说并不是百分百保险的。
原文地址:[Avoiding memory leaks](http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html)
';
adb logcat 查看日志
最后更新于:2022-04-01 20:40:45
**使用 logcat 命令**
查看和跟踪系统日志缓冲区的命令logcat的一般用法是:
~~~
[adb] logcat [
';
adb shell top
最后更新于:2022-04-01 20:40:43
PID:进程在系统中的ID
CPU% - 当前瞬时所以使用CPU占用率
#THR - 程序当前所用的线程数
UID - 运行当前进程的用户id
Name - 程序名称android.process.media
VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
';
adb shell 命令
最后更新于:2022-04-01 20:40:41
adb 概述
SDK的Tools文件夹下包含着Android模拟器操作的重要命令adb,adb的全称为(Android Debug Bridge就是调试桥的作用。通过adb我们可以在Eclipse中方面通过DDMS来调试Android程序。借助这个工具,我们可以管理设备或手机模拟器的状态。还可以进行以下的操作:
1、快速更新设备或手机模拟器中的代码,如应用或Android 系统升级;
2、在设备上运行shell命令;
3、管理设备或手机模拟器上的预定端口;
4、在设备或手机模拟器上复制或粘贴文件;
adb在集成开发环境中的工作
adb的工作方式比较特殊采用监听Socket TCP 5554等端口的方式让IDE和Qemu通讯,默认情况下adb会daemon相关的网络端口,所以当我们运行Eclipse时adb进程就会自动运行。
1.通过adb可以轻松的执行Linux Shell命令,如adb shell dir 就是列举目录,在Linux中根目录为/而不是Windows上的C盘、D盘。
2.安装apk程序到模拟器则执行adb install android123.apk,这样名为android123的安装包就会安装到Android模拟器中,前提是android123.apk文件需要放到SDK/Tools目录下。
3.向emulator传送文件, 使用adb push android123.txt /tmp/android123.txt命令可以把SDK/Tools下的android123.txt文件传输到模拟器的/tmp/文件夹中,需要注意的是/tmp/文件夹中内容会在Android模拟器重新启动时清空。
4.从Android仿真器中回传文件到电脑
通过adb pull /tmp/android123.txt android123.txt命令就会把仿真器的tmp文件夹下android123.txt文件回传到电脑SDK/Tools目录下。
adb 常用命令
1、安装应用到模拟器:
adb install
卸载命令
adb uninstall com.***.***.**** 卸载命令参数必须是总包名
2、进入设备或模拟器的shell:
adb shell
通过上面的命令,就可以进入设备或模拟器的shell环境中,在这个Linux Shell中,你可以执行各种Linux的命令,另外如果只想执行一条 shell命令,可以采用以下的方式:
adb shell [command]
如:adb shell dmesg会打印出内核的调试信息。
3、发布端口:
你可以设置任意的端口号,做为主机向模拟器或设备的请求端口。如:
adb forward tcp:5555 tcp:8000
4、复制文件:
你可向一个设备或从一个设备中复制文件,
复制一个文件或目录到设备或模拟器上:
adb push
如:adb push test.txt /tmp/test.txt
从设备或模拟器上复制一个文件或目录:
adb pull
如:adb pull /addroid/lib/libwebcore.so .
5、搜索模拟器/设备的实例:
取得当前运行的模拟器/设备的实例的列表及每个实例的状态:
adb devices
6、查看bug报告:
adb bugreport
7、记录无线通讯日志:
一般来说,无线通讯的日志非常多,在运行时没必要去记录,但我们还是可以通过命令,设置记录:
adb shell
logcat -b radio
8、获取设备的ID和序列号:
adb get-product
adb get-serialno
9、访问数据库SQLite3
adb shell
sqlite3
';
adb shell dumpsys 命令 查看内存
最后更新于:2022-04-01 20:40:38
android程序内存被分为2部分:native和dalvik,dalvik就是我们平常说的java堆,我们创建的对象是在这里面分配的,而bitmap是直接在native上分配的,对于内存的限制是 native+dalvik 不能超过最大限制。android程序内存一般限制在16M,当然也有24M的。
用以下命令可以查看程序的内存使用情况:
adb shell dumpsys meminfo $package_name or $pid //使用程序的包名或者进程id
用com.tencent.qqpimsecure为例:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392beb894d.gif)
具体每一项代表什么,参考:[http://stackoverflow.com/questions/2298208/how-to-discover-memory-usage-of-my-application-in-android#2299813](http://stackoverflow.com/questions/2298208/how-to-discover-memory-usage-of-my-application-in-android#2299813),我们比较关心的是这2行:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569392bec867a.gif)
其中size是需要的内存,而allocated是分配了的内存,对应的2列分别是native和dalvik,当总数也就是total这一列超过单个程序内存的最大限制时,OOM就很有可能会出现了。
多数时候,发生OOM 都是在做一些跟图片相关的操作,以下提出一些建议尽量可以减少这种情况的发生:
1.decode bitmap 的时候,尽量配置下Options,例如:inSameSize
2.Bitmap使用完以后,调用 bitmap.recycle()来释放内存
3.如果应用是基于图片的应用,尽量采用LazyLoad和DymanicRecycle
4.decode bitmap 的时候,将decode代码 try catch 出来,catch oom error,避免程序crash,可以在catch里面做一些释放内存操作
';
前言
最后更新于:2022-04-01 20:40:36
> 原文出处:[移动开发专栏文章](http://blog.csdn.net/column/details/android-performance.html)
> 作者:[张兴业](http://blog.csdn.net/xyz_lmn)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
#Android性能优化
> 介绍Android系能优化方法及性能分析工具
';