打开Hierachy Viewer
- 配置环境变量为在真机上使用Hierarchy Viewer分析性能做准备
将手机调整到开发者模式在这里就不罗嗦了,添加环境变量:
ANDROID_HVPROTO
ddm
配置完成后,重启计算机 - 打开Hierarchy Viewer进行分析
在手机上打开想要调试的APP(正式打包的不行)
到D:\android\sdk\tools路径下,双击monitor.bat文件,你可能会有疑惑不是hierarchyviewer.bat吗?没关系,仅仅是双击hierarchyviewer.bat depressed,如果提示在xx路径下面找不到jre之类的信息,把你jdk按照目录下的jre文件夹直接copy一份到指定的位置,再次启动即可。
![这里写图片描述]
选中要分析的APP,点击右上角的按钮。
如果没有出现红黄绿色的按钮和相关的测试数据,在主要显示区中选中某一个节点,点击右上角的一个三色的按钮,就ok了。
红黄绿含义和对布局性能分析的指导
当APP性能低下的时候,仅仅表明红色dot可能存在问题。由于这里的颜色值是一个相对值,总是会有一个最慢的节点,确保它应该是最慢的。
- 如果red dot在一个叶子节点或者一个只有几个子节点的ViewGroup上,可能会存在一些问题。APP整体表现可能不坏,但是你要意识到那个节点为什么是红色的!可以使用Systrace或者 TraceView做进一步的分析。
- 如果ViewGroup的Measure 是红色的,要分析一下它的子节点。
- 如果View存在黄色甚至红色dot,可能在手机上的运行效率并不慢,可能是由于view的数目过多造成的。可以使用Systrace或者 TraceView做进一步的分析。
- 如果一个层级结构的根节点measure dot是红色的,layout dot是红色的,draw dot是黄色的,这是一种非常典型的情况,因为它是所有节点的根节点。
- 如果一个有20+ view的层级结构中,一个叶子节点draw dot是红色的,那肯定是问题,检查一下它的onDraw方法。
使用Hierarchy Viewer的简单例子
slow.xml文件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/iv"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@null"
android:src="@drawable/ic_launcher" />
<LinearLayout
android:id="@+id/ll_right"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#ff0000"
android:text="This is Title!" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4"
android:background="#00ff00"
android:text="This is Content!" />
</LinearLayout>
</LinearLayout>
MainActivity代码如下:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slow);
}
}
使用Hierarchy Viewer分析如下:
这里在强调一下这里都是相对值,单纯的看Measure/Layout/Draw没有意义。由于手机或者PC CPU负载的变化每一次获取的图片都可能不一样,可以通过点击上图的三色按钮进行刷新。这里发现id/ll_right的Measure是红色的,这里符合提到的第一条和第二条,分析一下id/ll_right的子节点, 应该很快发现,Android中不提倡使用weight,咱们这里使用了weight的嵌套,更是大忌。官方文档是这么说的
It is a common misconception that using the basic layout structures leads to the most efficient layouts.
However, each widget and layout you add to your application requires initialization, layout, and drawing.
Furthermore, ***nesting several instances of LinearLayout that use the layout_weight parameter can be especially expensive as each child needs to be measured twice.***
This is particularly important when the layout is inflated repeatedly, such as when used in a ListView or GridView.
使用layout_weight参数的多级嵌套LinearLayout,每一个孩子节点需要测量两次。
优化一下,修改一下布局参数:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:contentDescription="@null"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/iv"
android:background="#ff0000"
android:text="This is Title!" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tv_title"
android:layout_toRightOf="@id/iv"
android:background="#00ff00"
android:text="This is Content!" />
</RelativeLayout>
MainActivity代码如下:
package com.example.hierarchyviewdemo;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.improved);
final ImageView iv = (ImageView) findViewById(R.id.iv);
RelativeLayout.LayoutParams ivParams = (RelativeLayout.LayoutParams) iv
.getLayoutParams();
ivParams.width = getScreenWidth(this) / 5;
ivParams.height = RelativeLayout.LayoutParams.MATCH_PARENT;
final TextView titleView = (TextView) findViewById(R.id.tv_title);
RelativeLayout.LayoutParams titleParams = (RelativeLayout.LayoutParams) titleView
.getLayoutParams();
titleParams.width = RelativeLayout.LayoutParams.MATCH_PARENT;
titleParams.height = dip2px(this, 100) / 5;
}
public static int getScreenHeight(Activity packageContext) {
DisplayMetrics metrics = new DisplayMetrics();
packageContext.getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
return metrics.heightPixels;
}
public static int getScreenWidth(Activity packageContext) {
DisplayMetrics metrics = new DisplayMetrics();
packageContext.getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
return metrics.widthPixels;
}
public static int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}
看一下效果:
这里分析很粗错,仅仅起到一个抛砖引玉的作用,希望能给大家有点引导作用。
翻译地址
https://developer.android.com/tools/performance/hierarchy-viewer/profiling.html#InterpretingResults
http://developer.android.com/training/improving-layouts/optimizing-layout.html#Inspect