Android性能优化汇总
CPU的优化,从减轻加工View对象成Polygons和Texture来下手
View Hierarchy中包涵了太多的没有用的view,这些view根本就不会显示在屏幕上面,一旦触发测量和布局操作,就会拖累应用的性能表现。
如何找出里面没用的view呢?或者减少不必要的view嵌套。
工具:Hierarchy Viewer检测
一 Hierarchy Viewer使用
找不到工具的,Android Monitor路径:打开sdk目录下的tool文件夹中monitor.bat
三个圆点分别代表:测量、布局、绘制三个阶段的性能表现。
1)绿色:渲染的管道阶段,这个视图的渲染速度快于至少一半的其他的视图。
2)黄色:渲染速度比较慢的50%。
3)红色:渲染速度非常慢。
二 常见的布局优化
优化思想:查看自己的布局,层次是否很深以及渲染比较耗时,然后想办法能否减少层级以及优化每一个View的渲染时间。
1 merge 和ViewStub、RelativeLayout减少布局层级和加载
- merge: 当我们的布局是用的FrameLayout的时候,我们可以把它改成merge
可以避免自己的帧布局和系统的ContentFrameLayout帧布局重叠造成重复计算(measure和layout) - ViewStub: 当加载的时候才会占用。不加载的时候就是隐藏的,仅仅占用位置。
例如一个列表,优化前的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="horizontal"
android:paddingBottom="@dimen/chat_padding_bottom">
<ImageView
android:id="@+id/chat_author_avatar"
android:layout_width="@dimen/avatar_dimen"
android:layout_height="@dimen/avatar_dimen"
android:layout_margin="@dimen/avatar_layout_margin" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#78A"
android:background="@android:color/white"
android:orientation="horizontal">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:padding="@dimen/narrow_space"
android:gravity="bottom"
android:id="@+id/chat_author_name" />
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:textStyle="italic"
android:padding="@dimen/narrow_space"
android:id="@+id/chat_datetime" />
</RelativeLayout>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/narrow_space"
android:background="@android:color/white"
android:id="@+id/chat_text" />
</LinearLayout>
</LinearLayout>
使用RelativeLayout优化后
<?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/chat_author_avatar"
android:layout_width="@dimen/avatar_dimen"
android:layout_height="@dimen/avatar_dimen"
android:src="@drawable/alex" />
<TextView
android:id="@+id/chat_author_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/chat_author_avatar"
android:paddingLeft="@dimen/narrow_space"
android:text="XXX" />
<TextView
android:id="@+id/chat_datetime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingRight="@dimen/narrow_space"
android:text="AAA"
android:textStyle="italic" />
<TextView
android:id="@+id/chat_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/chat_datetime"
android:layout_toRightOf="@id/chat_author_name"
android:paddingBottom="@dimen/chat_padding_bottom"
android:paddingLeft="@dimen/narrow_space"
android:text="BBB" />
</RelativeLayout>
2 背景经常容易造成过度绘制。
手机开发者选项里面找到工具:Debug GPU overdraw 可以看到过度绘制的局域颜色变深
**解决的办法:**将主题添加的背景去掉
3 自定义控件通过裁剪处理过度绘制。
优化前,在Canvas上重复绘制:
public class CardsView extends View {
//图片与图片之间的间距
private int mCardSpacing = 150;
//图片与左侧距离的记录
private int mCardLeft = 10;
private List<Card> mDroidCards = new ArrayList<>();
private Paint paint = new Paint();
public CardsView(Context context) {
super(context);
initCards();
}
public CardsView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initCards();
}
public CardsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initCards();
}
/**
* 初始化卡片集合
*/
protected void initCards() {
Resources res = getResources();
mDroidCards.add(new Card(res, R.drawable.alex, mCardLeft));
mCardLeft += mCardSpacing;
mDroidCards.add(new Card(res, R.drawable.claire, mCardLeft));
mCardLeft += mCardSpacing;
mDroidCards.add(new Card(res, R.drawable.kathryn, mCardLeft));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Card c : mDroidCards) {
drawCard(canvas, c);
}
invalidate();
}
private void drawCard(Canvas canvas, Card c) {
canvas.drawBitmap(c.bitmap, c.x, 0f, paint);
}
}
通过裁剪canvas优化,只绘制显示的区域,注意canvas的恢复
public class OptimizationCardsView extends View {
//图片与图片之间的间距
private int mCardSpacing = 150;
//图片与左侧距离的记录
private int mCardLeft = 10;
private List<Card> mDroidCards = new ArrayList<>();
private Paint paint = new Paint();
public OptimizationCardsView(Context context) {
super(context);
initCards();
}
public OptimizationCardsView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initCards();
}
public OptimizationCardsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initCards();
}
/**
* 初始化卡片集合
*/
protected void initCards() {
Resources res = getResources();
mDroidCards.add(new Card(res, R.drawable.alex, mCardLeft));
mCardLeft += mCardSpacing;
mDroidCards.add(new Card(res, R.drawable.claire, mCardLeft));
mCardLeft += mCardSpacing;
mDroidCards.add(new Card(res, R.drawable.kathryn, mCardLeft));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < mDroidCards.size() - 1; i++) {
drawDroidCard(canvas, mDroidCards, i);
}
drawLastDroidCard(canvas, mDroidCards.get(mDroidCards.size() - 1));
invalidate();
}
/**
* 绘制最后一个Card
*
* @param canvas
* @param c
*/
private void drawLastDroidCard(Canvas canvas, Card c) {
canvas.drawBitmap(c.bitmap, c.x, 0f, paint);
}
/**
* 绘制Card
*
* @param canvas
* @param mDroidCards
* @param i
*/
private void drawDroidCard(Canvas canvas, List<Card> mDroidCards, int i) {
Card c = mDroidCards.get(i);
canvas.save();
canvas.clipRect(c.x, 0f, mDroidCards.get(i + 1).x, c.height);
canvas.drawBitmap(c.bitmap, c.x, 0f, paint);
canvas.restore();
}
}