1 Window

1.1 What is Window?

  • Window is an abstract class that provides a common set of apis for drawing Windows.
  • Window is responsible for the display in Android, which can be understood as a View carrier, responsible for the display of the View. –
  • PhoneWindow is the only subclass of Window.

For example, the mWindow property of an Activity is a Window object, which is actually a PhoneWindow object. This object is responsible for displaying the Activity. A DecorView is the root View of all views in an Activity, so the mWindow object is the carrier of the DecorView and is responsible for displaying the DecorView.

1.2 Window Type

type Z-ordered example
The application Window 1~99 Activity
The child Window 1000 ~ 1999 Dialog
The Window system 2000 ~ 2999 Toast
  • A child Window cannot exist on its own and must depend on the parent Window, for example, Dialog must depend on the existence of an Activity.
  • Window layering, the display of higher-level Windows is overwritten by lower-level Windows.

2 WindowManager

2.1 What is WindowManager?

WindowManager is a WindowManager, which is an interface that inherits the ViewManager interface.

public interface ViewManager/ / definition ofViewOf authorization{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

public interface WindowManager extends ViewManager {}// See that WindowManager also provides interface methods for adding, deleting, and modifying views
Copy the code

WindowManagerImpl is the concrete implementation class of WindowManager.

Method to get a WindowManagerImpl object:

  • context.getSystemService(Context.WINDOW_SERVICE)

  • context.getWindowManager()

2.2 Functions of WindowManager

In fact, the specific creation and implementation of Window is located in the system level service WindowManagerService, our local application is not directly access, so we need to use WindowManager to achieve communication with the system service, so that the system service create and display Windows. The process of interacting with WindowManagerService through WindowManager is an IPC process. So you can say that WindowManager is the portal to access Windows.

  • WindowManager is our only access to Windows, but it only provides add, delete and modify operations to View. So the core of manipulating a Window is the manipulation of the vector View.

2.3 Creating Windows using WindowManager

By calling the addView method of the WindowManagerImpl object, the system window service will create a window for us and add the View we provide to the window.

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());
}
Copy the code
  • AddView method need to pass in a View object and a WindowManager LayoutParams object. WindowManager. LayoutParams attributes which are frequently used with flags and type, through our flags set properties window, through the type Settings window types.

As you can see, WindowManagerImpl is implemented internally by delegating a member variable to mGlobal, which is a WindowManagerGlobal object.

public final class WindowManagerImpl implements WindowManager {...private finalWindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); . }Copy the code

WindowManagerGlobal is a singleton pattern, that is, there is only one WindowManagerGlobal instance in a process and all WindowManagerImpl objects delegate to this instance.

// The classic lazy thread-safe singleton (remember the double lock and static inner class implementations...)
private static WindowManagerGlobal sDefaultWindowManager;

private WindowManagerGlobal(a) {}public static WindowManagerGlobal getInstance(a) {
    synchronized (WindowManagerGlobal.class) {
        if (sDefaultWindowManager == null) {
            sDefaultWindowManager = new WindowManagerGlobal();
        }
        returnsDefaultWindowManager; }}Copy the code
  • Windows ManagerGlobal maintains four collections to centrally manage information for all Windows in the process:
  private final ArrayList<View> mViews = new ArrayList<View>();
  private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
  private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
  private final ArraySet<View> mDyingViews = new ArraySet<View>();
Copy the code
attribute A collection of role
mViews ArrayList<View> It stores the View of all the Windows
mRoots ArrayList<ViewRootImpl> It stores the view wrootimPL for all Windows
mParams ArrayList<WindowManager.LayoutParams> Store layout parameters for all Windows
mDyingViews ArraySet<View> It stores View objects that are about to be deleted or View objects that are being deleted

WindowManager’s addView method delegates to mGlobal’s addView method.

WindowManagerGlobal.addView

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) {
    // Check whether the parameters are valid
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (display == null) {
        throw new IllegalArgumentException("display must not be null");
    }
    if(! (paramsinstanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }
	// The child Window needs to adjust some of the layout parameters
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if(parentWindow ! =null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } else {
        final Context context = view.getContext();
        if(context ! =null&& (context.getApplicationInfo().flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) ! =0) {
            wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }
   
    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        ...
        // Create the ViewRootImpl object
        root = new ViewRootImpl(view.getContext(), display);
		// Set the layout properties of the View
        view.setLayoutParams(wparams);
		// Save the related information to the corresponding collection
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);

        try {
            root.setView(view, wparams, panelParentView, userId);// Call the setView method of the ViewRootImpl object.
        } catch(RuntimeException e) { ... }}}Copy the code

3 ViewRootImpl

3.1 What is viewrotimPL?

ViewRootImpl is a class that implements the ViewParent interface (which defines some of the “functions” of being a parent of a View).

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.ThreadedRenderer.DrawCallbacks {}
Copy the code

The Viewrotimpl is the link between Windows Manager and the DecorView (formerly ViewRoot). ViewRootImpl has many functions. It is responsible for the operation of the View in the Window, and is the initiator of the View drawing process and event distribution. The IPC interaction between WindowManager and WindowManagerService is also the responsibility of viewrotimPL, and many operations of mGlobal are implemented through ViewrotimPL.

PS: Seeing this, we can compare the relationship between Windows Manager and ViewGroup.

  • ViewGroup implements the ViewManager and ViewParent interfaces.
  • WindowManager implements the ViewManager interface, while its internal via ViewRootImpl to control the View, ViewRootImpl implements the ViewParent interface.

So the result of the collaboration of all the Windows managers in a process can be thought of as a window Group that manages all the Windows in that process, has many Windows inside, and can add, delete, and change those Windows. (Personal opinion)

3.2 Creation of ViewRootImpl

public ViewRootImpl(Context context, Display display, IWindowSession session,boolean useSfChoreographer) {
    mContext = context;
    mWindowSession = session;// An instance of IWindowSession passed in from Windows ManagerGlobal, which is the proxy for viewrotimPL to communicate with WMS.
    mDisplay = display;
    mThread = Thread.currentThread();// Save the current thread
    mFirst = true; //true adds the view for the first time
    mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,context); . }Copy the code
  • The ViewRootImpl saves the current thread to the mThread, and each time it processes a request from the control tree (such as a request to rearrange, redraw, change focus, etc.), the ViewRootImpl will determine whether the requesting thread and the mThread are the same, and will throw an exception if they are not. Since ViewRootImpl is created in the main (UI) thread, UI operations can only be run in the main thread. . The Activity is created in the Activity of ViewRootImpl handleResumeActivity method called windowManager. AddView (decorView).
  • AttachInfo is the internal class of the View. The AttachInfo object stores information about the window of the current View tree and sends it to each View in the View tree. Stored in each View’s own mAttachInfo variable. soAll views in the same View tree are bound to the same AttachInfo object and the same ViewRootImpl object.
    • View.getviewrootimpl Gets the ViewRootImpl object
    • The Window object can be obtained by obtaining the DecorView and then the ViewRootImpl object

3.3 Continue the Window creation process

The Viewrootimpl. setView method is the source of the View drawing process

ViewRootImpl.setView

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    setView(view, attrs, panelParentView, UserHandle.myUserId());
}

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,int userId) {
    synchronized (this) {
        if (mView == null) {... requestLayout(); . res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mDisplayCutout, inputChannel, mTempInsets, mTempControls); }}}Copy the code
public void requestLayout(a) {
    if(! mHandlingLayoutInLayoutRequest) { checkThread();// Determine whether the ViewRootImpl thread is created (the main thread in the Activity)
        mLayoutRequested = true; scheduleTraversals(); }}Copy the code
void scheduleTraversals(a) {
    if(! mTraversalScheduled) { mTraversalScheduled =true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();// Create a synchronization barrier (see Android messaging)
        mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);// Send an asynchronous message, and mTraversalRunnable is the callback to process this messagenotifyRendererOfFramePending(); pokeDrawLockIfNeeded(); }}final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
    @Override
    public void run(a) { doTraversal(); }}Copy the code
void doTraversal(a) {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);// Remove the synchronization barrier

        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }

        performTraversals();// The starting point of the View

        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false; }}}Copy the code

RequestLayout is called in viewrootimpl. setView to draw the View with mWindowSession (IWindowSession is a Binder object, The real implementation class is Session. The addToDisPlay method is called remotely to add the Window.

  • Why does requestLayout send asynchronous messages to the main thread to draw the View?

  • After the Activity’s onCreate calls the setContentView, just add the View to DecorView, DecorView drawing is in the Activity. The real handleResumeActivity method, This method finally calls back to the activity’s onResume method, so you’ll find that creating child threads in the onCreate method to update the UI will not fail.

  • PerformTraversals at the end of the rendering call onGlobalLayout() with dispatchOnGlobalLayout calling OnGlobalLayoutListener. So we can use the view. GetViewTreeObserver () addOnGlobalLayoutListener, The onGlobalLayout() method is implemented to render the callback (at least the measure and layout are finished)

  • In addition, when manually calling invalidate, postInvalidate, requestInvalidate will eventually call performTraversals to redraw the View.

One conclusion: A Window corresponds to a View and a ViewRootImpl object.