Android 中的 Window,是一个比较抽象的概念,总有一种说不清道不明的感觉,但是又非常重要。
Activity 是四大组件之一,可以说是我们学习 Android 接触的第一个知识点,它也承担着 UI 和交互的控制逻辑,是我们开发应用经常用到的;View 也是我们经常用到的,从 XML 布局编写到 Activity & Fragment 中 UI 展示变化等,我们也很熟悉;相比之下,Window 我们在平时的开发中用到的不多,相对来说比较陌生。这篇文章就从熟悉的 Activity 入手,理解 Window。
一. Window 的创建 & 添加
Window 和 Activity 有着紧密的联系,一个 Activity 拥有至少一个 Window 对象,在创建 Activity 的时候,也会创建一个 Window 对象,并且 Activity 会实现 Window 的一些回调接口。
在上篇文章 深入理解 Activity 的生命周期 中,我们从源码的角度分析了 Activity 的生命周期,在 Activity 对象创建完成之后,调用的 Activity 第一个方法并不是 onCreate
相关的方法,而是 attach
方法,在 attach
方法中我们创建了 Activity 对应的 Window 对象,代码如下
public class Activity extends ContextThemeWrapper implements ...... {
private Window mWindow;
private WindowManager mWindowManager;
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, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// 代码 1
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
// 代码 2
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
// 代码 3
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
}
}
在代码 1 处创建了 Window 对象,Window 是一个抽象类,其具体的实现类是 PhoneWindow 类
-
在代码 2 处设置了 Window 的 Callback 回调,用户的触摸 & 键盘等输入事件就是通过此接口回调到 Activity 中的,
Window#Callback
回调源码如下public abstract class Window { /** * API from a Window back to its caller. This allows the client to * intercept key dispatching, panels and menus, etc. */ public interface Callback { /** * Called to process key events. At the very least your * implementation must call * {@link android.view.Window#superDispatchKeyEvent} to do the * standard key processing. * * @param event The key event. * * @return boolean Return true if this event was consumed. */ public boolean dispatchKeyEvent(KeyEvent event); /** * Called to process a key shortcut event. * At the very least your implementation must call * {@link android.view.Window#superDispatchKeyShortcutEvent} to do the * standard key shortcut processing. * * @param event The key shortcut event. * @return True if this event was consumed. */ public boolean dispatchKeyShortcutEvent(KeyEvent event); /** * Called to process touch screen events. At the very least your * implementation must call * {@link android.view.Window#superDispatchTouchEvent} to do the * standard touch screen processing. * * @param event The touch screen event. * * @return boolean Return true if this event was consumed. */ public boolean dispatchTouchEvent(MotionEvent event); // ...... } }
-
在代码 3 处为 Window 对象设置了 WindowManager 对象, WindowManager 是一个 Interface,其实现类是 WindowManagerImpl 类,我们来看下,最后通过 WindowManagerImpl 的 createLocalWindowManager 方法创建了一个新的 WindowManagerImpl 方法,并且将 Window 自己传入 WindowManagerImpl 中,在 WindowManagerImpl 的 mParentWindow 持有 Window 的对象
public abstract class Window { /** * Set the window manager for use by this Window to, for example, * display panels. This is <em>not</em> used for displaying the * Window itself -- that must be done by the client. * * @param wm The window manager for adding new windows. */ 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); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); } }
public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); private final Context mContext; private final Window mParentWindow; private IBinder mDefaultToken; public WindowManagerImpl(Context context) { this(context, null); } private WindowManagerImpl(Context context, Window parentWindow) { mContext = context; mParentWindow = parentWindow; } public WindowManagerImpl createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow); } public WindowManagerImpl createPresentationWindowManager(Context displayContext) { return new WindowManagerImpl(displayContext, mParentWindow); } // ...... @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); } @Override public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.updateViewLayout(view, params); } // ...... @Override public void removeView(View view) { mGlobal.removeView(view, false); } @Override public void removeViewImmediate(View view) { mGlobal.removeView(view, true); } // ...... }
-
在 WindowManagerImpl 类中持有一个 WindowManagerGlobal 对象,WindowManagerGlobal 在整个应用进程中是以单例存在的,也就是说在整个应用进程中,所有的 Window 和 WindowManagerImpl 对象都对应着这个 WindowManagerGlobal 对象,其源码如下,在其中有几个变量非常重要
-
ArrayList<View> mViews
:存储所有 Window 所对应的 View -
ArrayList<ViewRootImpl>
:存储所有 Window 所对应的 ViewRootImpl -
ArrayList<WindowManager.LayoutParams>
:存储所有 Window 所对应的 WindowManager.LayoutParams -
ArraySet<View>
:存储所有即将被移除的 View
public final class WindowManagerGlobal { // WindowManagerGlobal 单例对象 private static WindowManagerGlobal sDefaultWindowManager; // IWindowManager & IWindowSession 用于和 WindowManagerService 通过 Binder 通信 private static IWindowManager sWindowManagerService; private static IWindowSession sWindowSession; private final Object mLock = new Object(); 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>(); // 私有构造方法 private WindowManagerGlobal() { } // 初始化方法 public static void initialize() { getWindowManagerService(); } public static WindowManagerGlobal getInstance() { synchronized (WindowManagerGlobal.class) { if (sDefaultWindowManager == null) { sDefaultWindowManager = new WindowManagerGlobal(); } return sDefaultWindowManager; } } // 创建 IWindowManager 对象 public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (sWindowManagerService != null) { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowManagerService; } } // 非常重要的方法,向 Window 中添加 View,在这里 Window 和 View 产生了关联 public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { // ...... } // 更新 Window 中的 View public void updateViewLayout(View view, ViewGroup.LayoutParams params) { // ...... } // 从 Window 中移除 View public void removeView(View view, boolean immediate) { // ...... } }
-
关于 Activity、Window、WindowManager、WindowManagerImpl、WindowManagerGlobal 这几个类的关系可以用如下图来表示可能更清晰一些
上面我们介绍了 Activity 中的 Window 是如何创建并添加,Activity 和 Window 之间的关系就算是清楚了。接着我们分析 View 是如何添加到 Window 上面的。
二. 创建 PhoneView & DecorView & mContentParent
还是从熟悉的知识入手,我们在创建好一个 Activity 类,在 Activity 的 onCreate
方法中都会调用 setContentView
方法为 Activity 设置 View 的
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
setContentView
的源码如下,其实是调用了 Window 的 setContentView
方法
public class Activity extends ContextThemeWrapper implements ... {
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
}
Window 是一个抽象类,其具体实现类是 PhoneWindow 类
public class PhoneWindow extends Window implements MenuBuilder.Callback {
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// 代码 1
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
// 代码 2
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
// 代码 3
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
- 在代码1 处,首先会判断
mContentParent
是否为空,若为空会调用installDecor()
方法。mContentParent
是 PhoneWindow 中非常重要的一个属性,由其英文注释可知:mContentParent 是 Window 放置 View 内容的容器,可能是 mDecor 本身,或者是 mDecor 的一个子 View。 - 在代码2 处,会通过 mLayoutInflater 将传入的 layoutResID 解析并放入 mContentParent 内
- 在代码3 处,得到设置的 Callback 回调对象,并调用
onContentChanged()
,通知 View 内容发生变化这儿其实就是在
Activity#attach
方法中设置的 Callback 回调对象
接下来我们看一下 installDecor()
方法,看看是如何创建 mDecor
和 mContentParent
对象的
private void installDecor() {
mForceDecorInstall = false;
// 代码 1
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
// 代码 2
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
// ......
}
}
- 在代码 1 处通过
generateDecor(-1)
方法生成一个mDecor
的实例对象 - 在代码 2 处通过
generateLayout(mDecor)
方法生成mContentParent
实例对象
generateDecor(int featureId)
方法源码如下,最后一行生成了一个 DecorView 的实例对象,DecorView
就是一个 FrameLayout 的子类,这里不做过多的分析
protected DecorView generateDecor(int featureId) {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
}
接下来看一下 generateLayout(mDecor)
源码,通过 mDecor
生成一个 mContentParent
对象
protected ViewGroup generateLayout(DecorView decor) {
// ...... 应用当前的 Theme
// 根据主题设置去选择 layoutResource
// 这个 layoutResource 就是 DecorView 的子 View 的布局
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
setCloseOnSwipeEnabled(true);
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
// 比较常见的是这个 layout 布局
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
layoutResource = R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
// If no other features and not embedded, only need a title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
// 通过 DecorView 的 onResourcesLoaded 方法将 layoutResource 设置为当前 DecorView 的内容
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
// 通过 android.R.id.content id 得到 contentParent, 它是 setContentView 的父视图
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
ProgressBar progress = getCircularProgressBar(false);
if (progress != null) {
progress.setIndeterminate(true);
}
}
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
registerSwipeCallbacks(contentParent);
}
// Remaining setup -- of background and title -- that only applies
// to top-level windows.
// 设置背景和标题
if (getContainer() == null) {
final Drawable background;
if (mBackgroundResource != 0) {
background = getContext().getDrawable(mBackgroundResource);
} else {
background = mBackgroundDrawable;
}
mDecor.setWindowBackground(background);
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
}
if (mTitleColor == 0) {
mTitleColor = mTextColor;
}
setTitleColor(mTitleColor);
}
mDecor.finishChanging();
return contentParent;
}
上面代码就是根据当前的 Theme 设置 Window 的样式,选择合适的 mContentParent 的 layout 布局,并将 mContentParent 加载到 DecorView 中。比较常见的 mContentParent 的 layout 布局是 R.layout.screen_title_icons
,其代码位于 /frameworks/base/core/res/res/layout/screen_title.xml
,内容如下,其中有个 android:id/title
的 title 和 android:id/content
容器,我们通过 setContentView 设置的 View 的 parentView 就是这个 android:id/content
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
style="?android:attr/windowTitleBackgroundStyle">
<TextView android:id="@android:id/title"
style="?android:attr/windowTitleStyle"
android:background="@null"
android:fadingEdge="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
在 generateLayout(DecorView decor)
方法中得到了 DecorView 的直接子 View 的 layout 布局 id,然后通过 DecorView#onResourcesLoaded
方法将其设置为 DecorView 的直接子 View,我们来分析下 onResourcesLoaded
源码
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
ViewGroup mContentRoot;
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
mStackId = getStackId();
if (mBackdropFrameRenderer != null) {
loadBackgroundDrawablesIfNeeded();
mBackdropFrameRenderer.onResourcesLoaded(
this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
getCurrentColor(mNavigationColorViewState));
}
mDecorCaptionView = createDecorCaptionView(inflater);
// 通过 LayoutInflater 加载 layoutResource 布局,通过 root 引用
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
// 将 root View 设置为 DecorView 的第 0 个 View
// Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
// 将 root 赋给 mContentRoot 引用
mContentRoot = (ViewGroup) root;
initializeElevation();
}
}
看到这里,Activity、PhoneWindow、DecorView、mContentParent 的关系基本上就搞清楚了,如下图所示:
到这儿其实并没有结束,我们上面都是在 Activity 的 create 阶段分析 PhoneWindow、DecorView、mContentParent 的创建,并没有分析 DecorView 是如何添加到 PhoneWindow 上的,DecorView 添加到 PhoneView 的过程在 Activity 的 resume 过程中完成
三. 向 PhoneView 添加 DecorView
在 ActivityThread 的 handleLaunchActivity
中执行完 create 阶段的方法之后,立即开始调用 handleResumeActivity
方法,开始执行 resume 过程,handleResumeActivity
方法如下
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
return;
}
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// 代码 1,调用 performResumeActivity 间接地调用 Activity 的 onResume 方法
// TODO Push resumeArgs into the activity for consideration
r = performResumeActivity(token, clearHide, reason);
if (r != null) {
final Activity a = r.activity;
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManager.getService().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// 代码 2,在添加 DecorView 到 Window 之前,将 DecorView 设置为不可见的
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
// 代码 3,此处很重要,将 WindowManager.LayoutParams.type 属性设置为 TYPE_BASE_APPLICATION = 1,代表此 Window 是一个应用级的窗口,在所有窗口的最低下
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 代码 4,在这儿调用 WindowManager 的 addView 方法,将 DecorView 添加到 Window 中
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r, false /* force */);
// ......
} else {
// If an exception was thrown when trying to resume, then
// just end this activity.
try {
ActivityManager.getService()
.finishActivity(token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
在代码 4 处,我们可以清楚的看到调用了 WindowManager 的 addView 方法,那我们接着分析,因为 WindowManager 是一个 Interface,其实现类是 WindowManagerImpl,我们来到 WindowManagerImpl 方法中,如下:
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);
}
// ......
}
其实是调用了 WindowManagerGlobal 的 addView 方法,
public final class WindowManagerGlobal {
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
// ......
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// ......
// 代码 1,从 mViews 中找到此 DecorView 的 index 的索引
int index = findViewLocked(view, false);
if (index >= 0) {
// 若在 mDyingViews 中存在此 DecorView,则直接调用对应的 ViewRootImpl.doDei() 方法
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
// 代码 2,新建一个 ViewRootImpl 对象
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
// 代码 3,将 DecorView、ViewRootImple、WindowManager.LayoutParams 添加到对应的 List 中
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// 调用 ViewRootImpl 的 setView 方法,开始执行 DecorView 的绘制过程
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
private int findViewLocked(View view, boolean required) {
final int index = mViews.indexOf(view);
if (required && index < 0) {
throw new IllegalArgumentException("View=" + view + " not attached to window manager");
}
return index;
}
}