Wang Gang ---- UI rendering performance optimization optimization (CPU and GPU principle, overdraw optimization, layout optimization)

First: GPU and CPU workflow and overdraw
we see an interface, the interface all painted things are done by the GPU, but how to paint is done by the cpu. To put it plainly, CPU is a method of calculating the drawing, GPU is how to draw the screen, CPU will result to the GPU.
Our optimization is also divided into two points: (1) cpu: reducing convert xml into objects of time; (2) GPU: reduce the time of redrawn;
what is overdraw?
The GPU rendering process, just as whitewash, layer by layer is, 16ms brush. This will result in the phenomenon of image covered with a layer or neither will be drawn at the bottom, resulting in unnecessary waste.
If you do not understand the principles of UI rendering, jabbed here android layout rendering process
View excessive drawing method:
Developer Options -> Hardware accelerated rendering ---> debug GPU overdraw.
There will be three options, the third is color blind choice, we choose the second. After selecting the second you will find our mobile phones become colorful.
Here Insert Picture Description
Activity time if only one page, the screen is white, add a layer of what appears light blue, this is called a layer overdraw (1xOverDraw), and so on. Five or more layers (4xOverdraw) are displayed in red.
II: Optimization excessive draw (mainly reduce the workload of the GPU)
optimization 1 :: xml layout and background color windowBackgroud conflict
solution getWindow () setBackgroundDrawable (null); set to null. Or a method modeled on an article in solving black and white screen settings.
Optimization 2: Layout not arbitrarily set the background, especially the root layout.
Optimization 3: ImageView Do not set the background color. iv_imageView.setBackgroundColor (Color.TRANSPARENT);
Note android.R.color.transparent not consume any performance.
`Code is as follows

 if (chat.getAuthor().getAvatarId() != 0) {
            Picasso.with(getContext()).load(chat.getAuthor().getAvatarId()).into(
                    chat_author_avatar);
            chat_author_avatar.setBackgroundColor(Color.TRANSPARENT);
        } else {
            Picasso.with(getContext()).load(android.R.color.transparent).into(
                    chat_author_avatar);
            chat_author_avatar.setBackgroundColor(chat.getAuthor().getColor());
        }

Controls whether to be transparent or opaque, CPU will go computing, but setting transparent, it does not go to the GPU rendering. Setting an opaque time, we will go to the GPU computing. This saves time GPU.
Optimization 4: In one case, such as licensing cards, certainly overlap problem occurs, as shown in FIG.
Here Insert Picture Description
We look to optimize the code before
DroidCard class

package com.example.android.mobileperf.render;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
//扑克牌实体类
public class DroidCard {
    //x坐标,y坐标我省略了。
    public int x;
    public int width;
    public int height;
	//一张扑克牌,是由一张图片构成的。
    public Bitmap bitmap;

    public DroidCard(Resources res,int resId,int x){
        this.bitmap = BitmapFactory.decodeResource(res,resId);
        this.x = x;
        this.width = this.bitmap.getWidth();
        this.height = this.bitmap.getHeight();
    }

}

Custom DroidCardsView

package com.example.android.mobileperf.render;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class DroidCardsView extends View {

    //图片与图片之间的间距
    private int mCardSpacing = 150;
    //图片与左侧距离的记录
    private int mCardLeft = 10;
    //存储图片
    private List<DroidCard> mDroidCards = new ArrayList<DroidCard>();

    private Paint paint = new Paint();

    public DroidCardsView(Context context) {
        super(context);
        initCards();
    }

    public DroidCardsView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initCards();
    }


     /**
     * 初始化卡片集合,初始化三张图片,三张图片坐标有一个偏移
     */
    protected void initCards(){
        Resources res = getResources();
        mDroidCards.add(new DroidCard(res, R.drawable.alex,mCardLeft));

        mCardLeft+=mCardSpacing;
        mDroidCards.add(new DroidCard(res, R.drawable.claire,mCardLeft));

        mCardLeft+=mCardSpacing;
        mDroidCards.add(new DroidCard(res, R.drawable.kathryn,mCardLeft));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
		//因为三张图片坐标有偏移,所以绘制list的时候三张图片会一张一张向右摆放。
        for (DroidCard c : mDroidCards) {
            drawDroidCard(canvas,c);
        }

        invalidate();
    }

    private void drawDroidCard(Canvas canvas, DroidCard c) {
        canvas.drawBitmap(c.bitmap,c.x,0f,paint);
    }

}

We use the layout

<?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:background="@android:color/white"
    android:orientation="vertical">
//自定义控件
    <com.example.android.mobileperf.render.DroidCardsView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Although the display so it can achieve the effect, but the UI drawing serious overlap. how should I solve this?
We can show that part of canvas cut down. Where to draw cut. Because the canvas is so big, it will not place more than handled. GPU does not care about the extra space.
We modify the class DroidCardsView

package com.example.android.mobileperf.render;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class DroidCardsView extends View {

    //图片与图片之间的间距
    private int mCardSpacing = 150;
    //图片与左侧距离的记录
    private int mCardLeft = 10;
    //存储图片
    private List<DroidCard> mDroidCards = new ArrayList<DroidCard>();

    private Paint paint = new Paint();

    public DroidCardsView(Context context) {
        super(context);
        initCards();
    }

    public DroidCardsView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initCards();
    }



    /**
     * 初始化卡片集合,初始化三张图片,三张图片坐标有一个偏移
     */
    protected void initCards(){
        Resources res = getResources();
        mDroidCards.add(new DroidCard(res, R.drawable.alex,mCardLeft));

        mCardLeft+=mCardSpacing;
        mDroidCards.add(new DroidCard(res, R.drawable.claire,mCardLeft));

        mCardLeft+=mCardSpacing;
        mDroidCards.add(new DroidCard(res, R.drawable.kathryn,mCardLeft));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
		   //因为三张图片坐标有偏移,所以绘制list的时候三张图片会一张一张向右摆放。
          for (DroidCard c : mDroidCards) {
            drawDroidCard(canvas,c);
           }
         *
         */
		//注意size-1,如果有三张图,我们只画两张,最后一张单独处理就行了。
        for (int i = 0; i < mDroidCards.size() - 1; i++){
            drawDroidCard(canvas, mDroidCards,i);
        }
        drawLastDroidCard(canvas,mDroidCards.get(mDroidCards.size()-1));

        invalidate();
    }

//    private void drawDroidCard(Canvas canvas, DroidCard c) {
//        canvas.drawBitmap(c.bitmap,c.x,0f,paint);
//    }

    /**
     * 绘制最后一个DroidCard
     * @param canvas
     * @param c
     */
    private void drawLastDroidCard(Canvas canvas,DroidCard c) {
        canvas.drawBitmap(c.bitmap,c.x,0f,paint);
    }

    /**
     * 绘制DroidCard,只绘制出裁剪出来的一部分
     * @param canvas
     * @param mDroidCards
     * @param i 第几张图片
     */
    private void drawDroidCard(Canvas canvas,List<DroidCard> mDroidCards,int i) {
        DroidCard c = mDroidCards.get(i);
        //保存当前画布
        canvas.save();
        //画布裁剪一个矩形出来,参数的意思是左上右下
        canvas.clipRect((float)c.x,0f,(float)(mDroidCards.get(i+1).x),(float)c.height);
        canvas.drawBitmap(c.bitmap,c.x,0f,paint);
        //画布还原
        canvas.restore();
    }
}

第三:布局的优化(主要减少CPU的工作量)
在sdk中有一个工具可以帮助我们做性能优化,D:\sdk\tools\bin目录下的uiautomatorviewer.bat工具。
介绍下android studio中的性能优化工具-Layout Inspector性能优化工具的使用
首先在android studio中找到它。
Here Insert Picture Description
选择你要查看的进程,一般会有很多进程,我们这里因为我只有一个项目,所以只有一个进程。
Here Insert Picture Description
查看所在进程的布局文件
Here Insert Picture Description
navigationBarBackground是我们的导航栏,statusBarBackgroud是最上面的状态栏。整个xml布局结构可以在左侧清楚的看到。
另外在D:\sdk\tools下的monitor.bat中,点击Hierarchy Viewer中可以看到Hierarchy Viewer。其效果与Layout Inspector是类似的。Hierarchy Viewer中有三个点:绿色表示该View的此项性能比该View Tree中超过50%的都要快;黄色表示该View的此项性能比该View Tree中超过50%的都要慢;红色表示该View的此项性能是View Tree中最慢的。
优化1::能在一个平面显示的内容,尽量只用一个容器。不要过多的布局嵌套
优化2:尽可能把相同的容器合并merge
当是父亲独生子的时候,可以使用merge合并,这样在树中会少一层,少一层CPU计算的东西就少了一份。
Here Insert Picture Description
LinearLayout所在的布局代码修改跟标签为merge





Note that when combined can not have an ID attribute LinearLayout
Optimization 3: include energy processing code reuse can reduce duplication of cpu. Can reuse code reuse as much as possible, do not reuse things can go write repeatedly, repeatedly writing will cause the CPU to repeat the same thing to calculate. For example, each page is used ToorBar.
When we first loaded include layout, from the CPU to GPU, this process is complete. After a good run into the GPU computing CPU. GPU will use these things do caching, the next time when need is taken out from the GPU to perform cache inside the CPU does not do so a second time to calculate.

Guess you like

Origin blog.csdn.net/qczg_wxg/article/details/89741141