当前位置:首页 > Windows程序 > 正文

底层剖析 Window 、Activity、 View 三者关系

2024-03-31 Windows程序

不管工作几年的 Android 工程师,或多或少都听说过 Window 的概念,并且隐隐约约感觉它在 Activity 与 View 之间应该发挥着某种连接的作用。但是如果需要说出这 3 者之间的关系,多数工程师不知道从何下手。

Activity 的 setContentView

Activity 是 Android 开发人员使用最频繁的 API 之一,最初在接触 Android 开发时,我始终认为它就是负责将 layout 布局中的控件渲染绘制出来的。原因很简单,每当我们想显示一个新的界面时,都是通过 start 一个新的 Activity 方式;对于想显示的内容或者布局,也只需要在 Activity 中添加一行 setContentView 即可,剩下的 Activity 都自动帮我们搞定。但是我们从来没有去创建一个 Window 来绑定 UI 或者 View 元素。

直到我点开 setContentView 源码的那一刻:

public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }

public Window getWindow() { return mWindow; }

显然 Activity 几乎什么都没做,将操作直接交给了一个 Window 来处理。getWindow 返回的是 Activity 中的全局变量 mWindow,它是 Window 窗口类型。那么它是什么时候赋值的呢?

记得上篇文章中分析 startActivity 的过程,最终代码会调用到 ActivityThread 中的 performLaunchActivity 方法,通过反射创建 Activity 对象,并执行其 attach 方法。Window 就是在这个方法中被创建,详细代码如下:

@UnsupportedAppUsage 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, IBinder assistToken) { attachBaseContext(context); mFragments.attachHost(null /*parent*/); mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(this); 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; ... 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;

在 Activity 的 attach 方法中将 mWindow 赋值给一个 PhoneWindow 对象,实际上整个 Android 系统中 Window 只有一个实现类,就是 PhoneWindow。

接下来调用 setWindowManager 方法,将系统 WindowManager 传给 PhoneWindow,如下所示:

public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { mAppToken = appToken; mAppName = appName; mHardwareAccelerated = hardwareAccelerated; if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); }

public WindowManagerImpl createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow); }

最终,在 PhoneWindow 中持有了一个 WindowManagerImpl 的引用。

PhoneWindow 的 setContentView

Activity 将 setContentView 的操作交给了 PhoneWindow,看下PhoneWindow的setContentView方法实现过程:

@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 // 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 { mLayoutInflater.inflate(layoutResID, mContentParent); } mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } mContentParentExplicitlySet = true; }

解释说明:

标红的1 处调用如果 mContentParent 为 null,则调用 installDecor 初始化 DecorView 和 mContentParent。

标红的2处将我们调用 setContentView 传入的布局添加到 mContentParent 中。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/43566.html

Jm-杰米博客Jamie
草根站长的技术交流乐园!IT不会不要紧快来好好学习吧!
  • 20786文章总数
  • 7494595访问次数
  • 建站天数
  • 友情链接