Analyzing the View Binding Process for Activity

Original Link: https://my.oschina.net/acidsweet1990/blog/260838
When we coding, the textbook code commonly used in Activity.onCreate() is:
setContentView(R.layout.main);
Then we can do this by:
View view=findViewById(R.id.helloworld);
Get a control, but how this is done is discussed in this article.
Enter the source code of the Activity and view the setContentView() and findViewById() functions to see the prototype:
/***
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     */
     public void setContentView( int layoutResID) {
        getWindow().setContentView(layoutResID);
    }
     /***
     * Set the activity content to an explicit view.  This view is placed
     * directly into the activity's view hierarchy.  It can itself be a complex
     * view hierarhcy.
     *
     * @param view The desired content to display.
     */
     public void setContentView(View view) {
        getWindow().setContentView(view);
    }
They are all related ways to get an instantiated object for Windows through getWindow().
Window is an abstract class.What is this subclass of Windows?

It's PhoneWindow, so why is it is not discussed here.Interested students can view this blog:

http://www.cppblog.com/fwxjj/archive/2013/01/13/197231.html

Next let's take a look at the source code for entering PhoneWindow.PhoneWindow is under the package com.android.internal.policy.impl.
@Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }
The above is the setContentView implementation in PhoneWindow, while findViewById() is implemented in Window:
/**
     * Finds a view that was identified by the id attribute from the XML that
     * was processed in {@link android.app.Activity#onCreate}.  This will
     * implicitly call {@link #getDecorView} for you, with all of the
     * associated side-effects.
     *
     * @return The view if found or null otherwise.
     */
    public View findViewById(int id) {
        return getDecorView().findViewById(id);
    }
Let's analyze one by one, starting with setContent(), where the key code is this line:
mLayoutInflater.inflate(layoutResID, mContentParent);
It instantiates the layout pointed to by the layoutResID into a view and hangs behind the mContentParent.After you hook up, all that remains is the drawing of the view, which is not a press table.
Next comes findViewById(), which calls DecorView.findViewById(). DecorView is PhoneWindow's internal class, which represents the top view of the entire window. By default, it has two subviews, one showing a gray Title (titlebar) and the other showing the area of the program.For more detailed information on DecorView, you can refer to: http://www.cnblogs.com/beenupper/archive/2012/07/13/2589749.html
DecorView is actually a subclass of FrameLayout, follow up on FrameLayout!!!findViewById()... was not found inside FrameLayout. Entering the parent ViewGroup of FrameLayout was still not found, and went deeper... until View.Bingo!
/**
     * Look for a child view with the given id.  If this view has the given
     * id, return this view.
     *
     * @param id The id to search for.
     * @return The view that has the given id in the hierarchy or null
     */
    public final View findViewById(int id) {
        if (id < 0) {
            return null;
        }
        return findViewTraversal(id);
    }
It calls findViewTraversal() very comfortably, but note that ViewGroup is Override for this method, so you need to go into ViewGroup to see findViewTraversal().
/**
     * {@hide}
     */
    @Override
    protected View findViewTraversal(int id) {
        if (id == mID) {
            return this;
        }
 
        final View[] where = mChildren;
        final int len = mChildrenCount;
 
        for (int i = 0; i < len; i++) {
            View v = where[i];
 
            if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
                v = v.findViewById(id);
 
                if (v != null) {
                    return v;
                }
            }
        }
 
        return null;
    }
There is still something to note here:
First of all:
if (id == mID) {
             return this ;
        }
The mID is the ID of this View, that is, findViewById() is find to baseview.Then:
final View[] where = mChildren;
         final int len = mChildrenCount;
         for ( int i = 0 ; i < len; i ++ ) {
            View v = where[i];
 
             if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0 ) {
                v = v.findViewById(id);
 
                 if (v != null) {
                     return v;
                }
            }
        }
         return null;
Get all the sub-views of ViewGroup, and then loop to see if view.getId()==id exists in the sub-view of the query.There's actually a recursive process hidden here, and at < Two cornerstones of Android's UI >In, we know that View and ViewGroup are combinations using Composite, and ViewGroup is a subclass of View.So v.findViewById() may call findViewById() of View or ViewGroup, and the source code of View.findViewById() is also pasted here.
/**
     * Look for a child view with the given id.  If this view has the given
     * id, return this view.
     *
     * @param id The id to search for.
     * @return The view that has the given id in the hierarchy or null
     */
    public final View findViewById(int id) {
        if (id < 0) {
            return null;
        }
        return findViewTraversal(id);
    }
View.findViewById() simply checks if the ID equals View's own id, thereby guaranteeing the convergence of this depth-first traversal.
Through findViewById(), we know that using findViewById() in an Activity is actually a findViewById() that calls DecorView, the top-level view of the Window s;
We know more about why findViewById() sometimes returns null, and why we sometimes need to specify a baseView for findViewById(), such as:
baseView.findViewById(R.id.helloworld);

--------------------------------------------------------------------------------

If there are any errors in the text, you are welcome to point out.

Reprinted at: https://my.oschina.net/acidsweet1990/blog/260838

Tags: Android Windows Attribute xml

Posted on Thu, 12 Sep 2019 13:08:53 -0700 by DoD