1 Window、WindowManager 和 WMS
Window is an abstract class, and the specific implementation class is PhoneWindow, which manages View. WindowManager is an interface class, inherited from the interface ViewManager, it is used to manage Window, and its implementation class is WindowManagerImpl. If we want to add, update and delete Window (View), we can use WindowManager. WindowManager will hand over the specific work to WMS. WindowManager and WMS communicate across processes through Binder. WMS has many system services The API will not be exposed to WindowManager, which is somewhat similar to the relationship between ActivityManager and AMS.
The relationship between Window, WindowManager and WMS can be briefly represented by the following figure:
Window contains View and manages View. Window is represented by a dotted line because Window is an abstract concept used to describe a window. It does not really exist. The entity of Window is actually View. WindowManager is used to manage Window, and the functions provided by WindowManager will eventually be processed by WMS.
2 Associated classes of WindowManager
Here are the relevant classes:
public abstract class Window {
}
public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
public interface WindowManager extends ViewManager {
}
public interface ViewManager {
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
}
public final class WindowManagerGlobal {
}
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
}
**WindowManager is an interface class that inherits from the interface ViewManager. Three methods are defined in ViewManager, which are used to add, update and delete View respectively. **As shown below:
// /frameworks/base/core/java/android/view/ViewManager.java
public interface ViewManager {
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
**WindowManager also inherits these methods, and the parameters passed in by these methods are all View types, indicating that Window exists in the form of View. While inheriting ViewManager, WindowManager adds many functions, including constants related to Window type and hierarchy, internal classes and some methods, two of which are added according to the characteristics of Window, **as shown below:
// /frameworks/base/core/java/android/view/WindowManager.java
public Display getDefaultDisplay();
public void removeViewImmediate(View view);
WindowManager.getDefaultDisplay()
The method can know which screen the WindowManager instance has added the Window to, in other words, it is the screen (Display) managed by the WindowManager. WindowManager.removeViewImmediate
The method is fixed in this method to exchange the money back and execute it immediately View.onDetachedFromWindow()
to complete the related destruction work of the incoming View.
**Window is an abstract class, and its concrete implementation class is PhoneWindow. The method will be called during the startup of the Activity ActivityThread.performLaunchActivity
, and the method will be called in this method Activity.attach
. PhoneWindow is Activity.attach
created in the method. **As follows:
// /frameworks/base/core/java/android/app/Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window); // 1
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); // 2
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
PhoneWindow is created at Note 1, and the method is called at Note 2 PhoneWindow.setWindowManager
, which is implemented in PhoneWindow's parent class Window. As follows:
// /frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); // 1
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); // 2
}
If it is passed in WindowManager == null
, the method will be called at Note 1 Context.getSystemService
, and the service name Context.WINDOW_SERVICE
(the value is window) will be passed in, which is specifically implemented in ContextImpl, as follows:
// /frameworks/base/core/java/android/app/ContextImpl.java
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
ContextImpl.getSystemService
The method is called in the method SystemServiceRegister.getSystemService
:
// /frameworks/base/core/java/android/app/SystemServiceRegistry.java
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
new HashMap<Class<?>, String>();
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
static abstract interface ServiceFetcher<T> {
T getService(ContextImpl ctx);
}
SYSTEM_SERVICE_FETCHERS is a HashMap type of data, which is used to store the name of the service, so Context.WINDOW_SERVICE
what exactly does the incoming correspond to? Then look down:
// /frameworks/base/core/java/android/app/SystemServiceRegistry.java
private SystemServiceRegistry() {
}
static {
...
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx); // 1
}});
...
}
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
Several methods are called in the static code block of SystemServieRegistry registerService
. registerService
The method will store the name of the incoming service in SYSTEM_SERVICE_FETCHERS
. It can be seen from Note 1 that the incoming Context.WINDOW_SERVICE
corresponds to WindowManagerImpl
the instance, so it is concluded that Context.getSystemService
the method gets WindowManagerImpl
the instance. Go back to Window.setWindowManager
the method and get the method at Note 1 WindowManagerImpl.createLocalWindowManager
:
// /frameworks/base/core/java/android/view/WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
WindowManagerImpl.createLocalWindowManager
The method is also created WindowManagerImpl
. The difference is that WindowManagerImpl
the Window that was created is passed in as a parameter when creating this time, so that WindowManagerImpl
it holds a reference to the Window and can operate on the Window. For example, adding a View in the middle of the Window will call the WindowManagerImpl.addView
method. As follows:
// /frameworks/base/core/java/android/view/WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); // 1
}
The method is called at Note 1 WindowManagerGlobal.addView
, and the last parameter mParentWindow
is the Window mentioned above. It can be seen that although WindowManagerImpl is the implementation class of WindowManager, it does not implement any functions, but delegates the function implementation to it WindowManagerGlobal
. What is used here is bridge mode. Let's take a look at WindowManagerImpl
how to define when in WindowMangerGlobal
, as follows:
// /frameworks/base/core/java/android/view/WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); // 1
private final Context mContext;
private final Window mParentWindow; // 2
...
private WindowManagerImpl(Context context, Window parentWindow) {
mContext = context;
mParentWindow = parentWindow; // 3
}
...
}
It can be seen in Note 1 that WindowManagerGlobal
is a singleton, indicating that there is only one WindowManagerGlobal
instance of in a process. The code at Note 2 combined with the code at Note 3 shows WindowManagerImpl
which Window this instance will be a sub-Window of, which means that there may be multiple instances of WinodwManagerImpl in one process.
The following is the sequence diagram:
PhoneWindow inherits from Window, and Window setWindowManager
is associated with WindowManager through the method. WindowManager inherits from the interface ViewManager, and WindowManagerImpl is the implementation class of the WindowManager interface, but the specific functions will be entrusted to WindowManagerGlobal for implementation.
3 Window operation
WindowManager manages Window, such as adding, updating and deleting Window. For these operations, they are finally handled by WMS. The operation of the window is divided into two parts, one part is the WindowManager processing part, and the other part is the WMS processing part.
Window is divided into three categories, namely Application Window (application window), Sub Window (sub window), System Window (system window). The process of adding different types of windows will be different, but for the WMS processing part, add The process is basically the same, and WMS basically treats these three types of windows "equally":
3.1 Adding process of system window
Window is divided into three types, and the process of adding different types of Window is also different. Here we mainly talk about the process of adding system windows. The process of adding system windows will also vary according to different types. Here we mainly take the system window StatusBar as an example. StatusBar is an important part of SystemUI. Specifically, it refers to the system status bar, which is used to display information such as time, power and signal. .
First look at StatusBar.addStatusBarWindow()
the method, which is responsible for adding a Window to the StatusBar, as shown below:
// /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
private void addStatusBarWindow() {
makeStatusBarView(); // 1
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
mRemoteInputController = new RemoteInputController(mHeadsUpManager);
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); // 2
}
StatusBar
View for construction at Note 1 . The method is called at Note 2 StatusBarWindowManager.add
, and StatusBar
the view ( mStatusBarWindow
) and StatusBar
the height of are passed in, StatusBarWindowManager.add
the method is as follows:
// /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
public void add(View statusBarView, int barHeight) {
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
barHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR, // 1
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar");
mLp.packageName = mContext.getPackageName();
mStatusBarView = statusBarView;
mBarHeight = barHeight;
mWindowManager.addView(mStatusBarView, mLp); // 2
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
}
Firstly LayoutParams
configure StatusBar
the properties of the view by creating , including Width
, Height
, Type
, Flag
, Gravity
, SoftInputMode
etc. The key is in Note 1, which is set TYPE_STATUS_BAR
, indicating that StatusBar
the window type of the view is the status bar. The method is called at Note 2 WindowManager.addView
, addView
the method is defined in WindowManager
the parent class interface of ViewManager
, and addView
the method is WindowManagerImpl
implemented in , as shown below:
// /frameworks/base/core/java/android/view/WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerImpl.addView
The type of the first parameter of the method is View
, indicating that the window also View
exists in the form of . WindowManagerImpl.addView
method calls WindowManagerGlobal.addView
the method, as follows:
// /frameworks/base/core/java/android/view/WindowManagerGlobal.java
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>();
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams); // 1
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
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) {
...
root = new ViewRootImpl(view.getContext(), display); // 2
view.setLayoutParams(wparams);
mViews.add(view); // 3
mRoots.add(root); // 4
mParams.add(wparams); // 5
try {
root.setView(view, wparams, panelParentView); // 6
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
Before introducing WindowManagerImpl.addView
the method, we must first understand the 3 lists WindowManagerGlobal
maintained in and related to the operation. These 3 lists will be involved in the process of adding, updating and deleting windows. They are list ( ), layout parameter list ( ) and list ( ).Window
View
ArrayList<View> mViews
ArrayList<WindowManager.LayoutParams> mParams
ViewRootImpl
ArrayList<ViewRootImpl> mRoots
Next, analyze WindowManagerGlobal.addView
the method, first checking the parameters view
, params
and . At Note 1, if the current window is a child window, the object of type of the child window will be adjusted accordingly display
according to the parent window . Save the added to the list at Note 3. Save the parameters of the window to the layout parameter list at Note 5. Created at Note 2 and assigned to , then stored in the list at Note 4 . In Note 6, the window and window parameters are set in via the method , it can be seen that the operation of adding a window is performed through .WindowManager.LayoutParams
wparams
View
View
ViewRootImpl
root
root
ViewRootImpl
setView
ViewRootImpl
ViewRootImpl
ViewRootImpl
There are many responsibilities, mainly the following:
View
the root of the tree and manageView
the tree;- Triggered
View
measurement, layout and drawing; - A transit point for input events;
- management
Surface
; - Responsible for
WMS
inter-process communication with ;
After understanding ViewRootImpl
the responsibilities, let's look at ViewRootImpl.setView
the method:
// /frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets,
mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
...
}
In the method, the method ViewRootImpl.setView
is mainly called , which is of type. It is an object, used for inter-process communication, and is the agent of the terminal. Its implementation of the terminal is that the previous code logic is run in the local process, and the method is Run in the process ( process) where is as follows:mWindowSession.addToDisplay
mWindowSession
IWindowSession
Binder
IWindowSession
Client
Server
Session
Session.addToDisplay
WMS
system_server
As can be seen from the above figure, the local process ViewRootImpl
wants WMS
to communicate with Session
, so Session
why is it included in WMS
? Then look down Session.addToDisplay
the method, as follows:
// /frameworks/base/telecomm/java/android/telecom/Logging/Session.java
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
Session.addToDisplay
The method is called in the method , WMS.addWindow
and itself is Session
passed in as a parameter. Each application process will correspond to one Session
, WMS
which will be used ArrayList
to save these Session
, which is why is WMS
included in the above figure Session
. In this way, the remaining work is handed over WMS
to , WMS
which will allocate the added window Surface
and determine the display order of the windows. It can be seen that the canvas is responsible for displaying the interface Surface
, not the window itself. will pass the s WMS
it manages to the , which will be blended and drawn to the screen.Surface
SurfaceFlinger
SurfaceFlinger
Surface
The following is StatusBar
the sequence diagram of the adding process of the system window:
3.2 Activity
Addition process
No matter what kind of window it is, its adding process WMS
is basically similar in the processing part, but there are some differences in permissions and window display order. However, WindowManager
the processing part will be different. Take the most typical application window Activity
as an example. Activity
During the startup process, if Activity
the process where is located does not exist, a new process will be created. After the new process is created, an instance representing the main thread will run ActivityThread
, ActivityThread
which manages the thread of the current application process, which is Activity
obviously used in the startup process of , when the interface needs to interact with the user, ActivityThread.handleResumeActivity
the method will be called, as shown below:
// /frameworks/base/core/java/android/app/ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume,
int seq, String reason) {
...
r = performResumeActivity(token, clearHide, reason); // 1
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager(); // 2
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l); // 3
} else {
a.onWindowAttributesChanged(l);
}
}
...
}
The method at comment 1 performResumeActivity
will eventually call Activity.onResume
the method. ViewManager
The object of type is obtained at Note 2 wm
, the method is called at Note 3 ViewManager.addView
, and addView
the method is WindowManagerImpl
implemented in , and the subsequent process StatusBar
has been described in the process of adding the system window above, the only thing that needs to be noted is ViewManager.addView
the first step of the method The first parameter is DecorView
, which indicates that Activity
the window will contain DecorView
.
3.3 Winodow
The update process
Window
The update process for Window
is similar to the add process for . The method needs to be called ViewManager.updateViewLayout
, updateViewLayout
which WindowManagerImpl
is implemented in , and WindowManagerImpl.updateViewLayout
the method will be called in WindowManagerGlobal.updateViewLayout
the method, as follows:
// /frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams); // 1
synchronized (mLock) {
int index = findViewLocked(view, true); // 2
ViewRootImpl root = mRoots.get(index); // 3
mParams.remove(index); // 4
mParams.add(index, wparams); // 5
root.setLayoutParams(wparams, false); // 6
}
}
1
Set the updated parameters at the comment View
to , 2
get the index of the window to be updated in View
the list at the comment , obtain the window according to the index in the list at the 3
comment , use the comment and the comment to update the layout parameter list, and call the method at the comment to The updated parameters are set into . method calls the method at the end, as follows:ViewRootImpl
ViewRootImpl
4
5
6
ViewRootImpl.setLayoutParams
ViewRootImpl
ViewRootImpl.setLayoutParams
ViewRootImpl.scheduleTraveesals
// /frameworks/base/core/java/android/view/ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); // 1
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
1
The translation at the comment Choreographer
is "dance guide", which is used to receive VSync
the signal of the display system and control the execution of some operations when the next frame is rendered. Choreographer.postCallback
method is used to initiate the added callback, which will be executed when the next frame is rendered. This added callback refers to the type 1
at the annotation , as follows:c
mTraversalRunnable
// /frameworks/base/core/java/android/view/ViewRootImpl.java
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
TraversalRunnable.run()
Call the method in the method as doTraversal()
follows:
// /frameworks/base/core/java/android/view/ViewRootImpl.java
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
In doTraversal
the method, the method is called performTraversals()
, performTraversals()
which makes the workflow of ViewTree
start View
, as follows:
// /frameworks/base/core/java/android/view/ViewRootImpl.java
private void performTraversals() {
try {
...
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); // 1
...
} catch (RemoteException e) {
}
if (!mStopped) {
...
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); // 2
}
...
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
if (didLayout) {
performLayout(lp, mWidth, mHeight); // 3
,,,
}
...
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw && !newSurface) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
performDraw(); // 4
}
...
}
The method at Note 1 relayoutWindow
will call IWindowSession
the relayout
method to update Window
the view, which is the same as the principle in 3.1, and the method will be called WMS
eventually relayoutWindow
. In addition, the method will call the , , and methods performTraversals
at Notes 2, 3, and 4 respectively , and they will call the , and methods inside them , which completes the workflow of . The view is updated in the method , and the workflow in is executed , thus completing the update of .performMeasure
performLayout
performDraw
View
measure
layout
draw
View
performTraversals
Window
Window
View
Window