XVII works View of (1) --- View draw basic knowledge

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/yz_cfm/article/details/90676956

First we look at the Android UI interface architecture:

    This figure is above the Android UI interface architecture diagram, Activity object is the Android System provided what we see UI interface. Can be seen from the figure, each contains a Window object Activity (Window class is abstract, is PhoneWindow Window class implementation class), Window object is generally achieved by a PhoneWindow in Android. PhoneWindow DecorView a View to the root of the entire application window . DecorView view window as the top interface, in general, will contain within it LinearLayout a vertical direction, in this LinearLayout there are two parts, the top is titleview (title bar), the following is the ContentView (content field). This is actually a ContentView FramLayout content of the id. When we create an event, call setContentView (R.layout.activity_main) in onCreate () method; when, in fact, is to  set the file to the layout activity_main.xml FrameLayout in. Down TitleView most cases (different versions, are subject to change) is the default ActionBar displayed.

    We know, by calling requestWindowFeature (Window.FEATURE_NO_TITLE) can display a full-screen interface, which is no title bar, leaving only ContentView. And the method to be called to take effect before setContentView method, is hidden below the title bar shows only ContentView code:

// 当继承自 Activity,并且 requestWindowFeature() 方法调用在 setContentView() 之前才会有效
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
    }
}

// 当继承自 AppCompatActivity 时,隐藏标题栏如下即可。
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(getSupportActionBar() != null){
            getSupportActionBar().hide();
        }
    }
}

    Here we should note that not calling the setContentView () method we can see that after the view displays. But after a callback ActivityManagerService onResume Activity () method, then the system will add to the whole DecorView PhoneWindow and allowed to be displayed, thereby rendering the final completion of the interface.

    Here we look at the top-level view DecorView how to add PhoneWindow in :

    After completion of the initialization Activity Window and added to the internal layout of the class DecorView PhoneWindow, ActivityThread class calls handleResumeActivity () method adds to PhoneWindow in top view DecorView:

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ...
            if (r.window == null && !a.mFinished && willBeVisible) {
                // 获取当前 activity 的 PhoneWindow 对象
                r.window = r.activity.getWindow();

                // 获取 PhoneWindow 对象的 DecorView(也就是顶层视图)
                View decor = r.window.getDecorView();

                // 设置 DecorView 不可见
                decor.setVisibility(View.INVISIBLE);

                // 获取当前 activity 的 WindowManagerImpl 对象
                ViewManager wm = a.getWindowManager();
               ...
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        // 标记 DecorView 已经添加到 PhoneWindow
                        a.mWindowAdded = true;
                        // WindowManagerImpl 将 DecorView 添加到 PhoneWindow 中
                        wm.addView(decor, l);
                    } else {
                        ...
                    }
                }
            ...
    }
}

    You can see the end by  addView WindowManagerImpl class () method:

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

    ...

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
    ...    
}

    Continue to track  WindowManagerGlobal class addView ():

public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
    ...
    ViewRootImpl root; 

    ...
    root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);

    try {
        // 将 DecorView 设置到 ViewRootImpl 对象中
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        ...
    }
}

    Continue to track ViewRootImpl class setView () method:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    ...
    // 将传过来的 DecorView 赋值给全局 mView 参数
    mView = view;

    // 标记已经添加了 DecorView 到窗口
    mAdded = true;
    ...

    // 请求开始布局
    requestLayout();
    ...
}

    Look requestLayout () method:

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

    Continue to   scheduleTraversals () method:

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        ...
        mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        ...
    }
}

    Before proceeding  doTraversal () method mTraversalRunnable in:

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {

    @Override
    public void run() {
        doTraversal();
    }
}

    Continue to track doTraversal () method:

void doTraversal() {
    if (mTraversalScheduled) {
        ...
        try {
            // 最终调用 performTraversals() 方法开始真正的 View 绘制流程
            performTraversals();
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
}

    Finally, look at the ViewRootImpl in  performTraversals () method:

private void performTraversals() {
    // 这个 mView 就是 DecorView 根布局
    final View host = mView;

    // mAdded赋值为true,因此条件不成立
    if (host == null || !mAdded)
        return;

    //是否正在遍历
    mIsInTraversal = true;

    //是否马上绘制View
    mWillDrawSoon = true;

    //顶层视图DecorView所需要窗口的宽度和高度
    int desiredWindowWidth;
    int desiredWindowHeight;

    //在构造方法中mFirst已经设置为true,表示是否是第一次绘制DecorView
    if (mFirst) {
        mFullRedrawNeeded = true;
        mLayoutRequested = true;

        //如果窗口的类型是有状态栏的,那么顶层视图DecorView所需要窗口的宽度和高度就是除了状态栏
        if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
                || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
            Point size = new Point();
            mDisplay.getRealSize(size);
            desiredWindowWidth = size.x;
            desiredWindowHeight = size.y;
        } else {
            //否则顶层视图DecorView所需要窗口的宽度和高度就是整个屏幕的宽高
            DisplayMetrics packageMetrics = mView.getContext().getResources().getDisplayMetrics();
            desiredWindowWidth = packageMetrics.widthPixels;
            desiredWindowHeight = packageMetrics.heightPixels;
        }
    }
    ...

    //获得view宽高的测量规格,mWidth和mHeight表示窗口的宽高,lp.widthhe和lp.height表示DecorView根布局宽和高
    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

    //执行测量操作
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    ...

    //执行布局操作
    performLayout(lp, desiredWindowWidth, desiredWindowHeight);
    ...

    //执行绘制操作
    performDraw();

}

    Through the above source tracking, we can know, draw process View is from ViewRootImpl object performTraversals () method begins . ViewRootImpl objects as a bridge between the WindowManager and DecorView. In  () internal method, after the measure (measure), layout (layout), Draw (drawing) process to eventually a three View drawn performTraversals, which measure is used to measure the width and height of the View, the View layout to determine place the parent container, while the draw is responsible for the View to draw on screen .

    By  performTraversals () method, we can see that it will eventually turn calls performMeasure (), performLayout (), performDraw () these three methods, complete these three methods are the top View of measure, layout and draw these three processes, wherein performMeasure will call the measure () method -> then call onMeasure () method -> Next, all the sub-elements measure the process, this time measure is passed back from the parent container to child element, and thus completing a measure process (the parent process is complete container measure). Then subelements repeated measure procedure parent container, and so forth is complete to traverse the entire tree View. Similarly, PerformLayout () and performDraw () and processes the transmission performMeasure () are similar, the only difference is, performDraw () in the transfer process is draw () method implemented by dispatchDraw (), but this does There is no essential difference.

    measure process determines the width and height of View, and after the measure is completed, can be obtained View width / height getMeasuredWidth () and geyMeasuredHeight () method , in almost all cases it will equate View final width / height, Of course there are special circumstances, will learn later.

    layout process determines the actual coordinates of the four vertices View View width / height, after completion, can be used to get the positions of the four vertices getTop (), getBottom (), getLeft () and getRight (), and by getWidth () and getHeight () method to get the final View width / height .

    draw process is the final decision of the View display, only after the completion of the draw method, content View the order presented on the screen.

    The following is a flowchart of object performTraversals ViewRootImpl () method:

 

Guess you like

Origin blog.csdn.net/yz_cfm/article/details/90676956