Activity的显示源码阅读

阅读对象:不适合新手
阅读时间:20分钟
源码分析基于Android 28
文章不定期更新,如有错误之处还望大佬指出,我会及时修改,避免误导他人。

前言

布局文件是如何在界面显示,首先我们知道界面是在Activity#setContentView()方法设置的,经过一些系列处理,当Activity#onResume()被触发回调后,用户才能看到界面,现在我们从这两个函数出发,追查下源码究竟是做了什么哪些工作呢,当前我们不妨从如下几个问题开始展开源码的阅读。

那么带着下面提问

  • ActivityManagerService是怎么跟Activity建立联系的?
  • PhoneWindow是什么?PhoneWindow的创建时机?
  • PhoneWindow中的WindowManager你知道是做什么的吗?
  • DecorView是什么?DecorView创建时机?
  • DecorView中的W对象你知道是做什么的吗?
  • XmlPullParser你清楚吗,布局xml文件是怎么转化成对应的View过程是?
  • 对于页面优化你知道该怎么做吗?

阅读源代码,下面贴的代码都是伪代码,主要是为了方便查看。

一 setContentView(…)

--> AppCompatActivity#setContentView(...)
@Override
public void setContentView(@LayoutRes int layoutResID) {
    // 交由委托类AppCompatDelegateImpl处理
    getDelegate().setContentView(layoutResID);
}

--> AppCompatDelegateImpl#setContentView(...)
@Override
public void setContentView(int resId) {
    // step 1.1
    ensureSubDecor();
    // contentParent是对开发者开放的内容容器
    ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
    contentParent.removeAllViews();
    // LayoutInflater.from返回Inflater的服务
    //  step 1.2 
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    mOriginalWindowCallback.onContentChanged();
}

ensureSubDecor()方法主要创建一个View,这个View就是mSubDecor,我们知道Android的根View是DecorView,那么最后mSubDecor肯定是会添加到根View上,根View是继承FrameLayout的ViewGroup,里面包含了状态栏、标题栏、和内容。开发者调用的setContentView(layoutResID)就是页面添加到内容ViewGroup添加layoutResID的过程。

step1.1 ensureSubDecor()

在window中创建decorView中,并且把subdecor添加进去到decorView中

--> AppCompatDelegateImpl#ensureSubDecor
private void ensureSubDecor() {
    if (!mSubDecorInstalled) {
        // 创建subDecor
        mSubDecor = createSubDecor();
    }
}

根据mSubDecorInstalled标志位判断是否创建subDecor,若false则调用createSubDecor()

--> AppCompatDelegateImpl#createSubDecor
private ViewGroup createSubDecor() {
      // 标注1.1.1
      TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
      ···
      // Now let's make sure that the Window has installed its decor by retrieving it
      // 标注1.1.2
      mWindow.getDecorView(); 
      ...
      // 标注1.1.3
      if (条件1) {
         subDecor = (ViewGroup) inflater.inflate(R.layout.xxx, null); 
      } else if(条件2) {
          subDecor = (ViewGroup) inflater.inflate(R.layout.xxx, null);
      }
      
      ...
      // Now set the Window's content view with the decor
      // 标注1.1.4
      mWindow.setContentView(subDecor);
    return subDecor;
}
标注1.1.1

获取样式主题文件设置窗口样式

标注1.1.2

确保window(PhoneWindow)中的decor初始化 ,window是在ActivityThread#attach中创建

--> mWindow.getDecorView(); 
--> PhoneWindow#getDecorView()
@Override
public final View getDecorView() {
    if (mDecor == null || mForceDecorInstall) {
        // 初始化Decor继续跟进查看
        installDecor();
    }
    return mDecor;
}

--> PhoneWindow#installDecor()
private void installDecor() {
    mForceDecorInstall = false;
    if (mDecor == null) {
        // mDecor通过generateDecor(-1)获得,并且在getDecorView()返回,继续跟进查看
        mDecor = generateDecor(-1);
        ...
    } else {
        mDecor.setWindow(this);
    }
    
    if (mContentParent == null) {
        // 获取id为com.android.internal.R.id.content的内容容器
        mContentParent = generateLayout(mDecor);
    }
    ...
}

--> PhoneWindow#generateDecor(...)
protected DecorView generateDecor(int featureId) {
    ...
    // 此时DecorView在PhoneWindow中创建,DecorView是一个view并且继承FrameLayout和接口WindowCallbacks。
    // 并且this代表当前PhoneWindow实例,传递到DecorView中,并且PhoneWindow也拥有DecorView实例,它们就建立起了联系。
    return new DecorView(context, featureId, this, getAttributes());
}
标注1.1.3

根据各种条件加载不同的subDecor布局文件

标注1.1.4

把subDecor添加到window的内容容器中

--> mWindow.setContentView(subDecor);
--> PhoneWindow#setContentView(...)
@Override
public void setContentView(View view) {
    setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}

--> PhoneWindow#setContentView(...)
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
    // 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.
    // 标注2中可以看出mContentParent不为null
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        // 没有动画清空内容容器中所有的view,确保添加之前容器没有其他的View。
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        view.setLayoutParams(params);
        final Scene newScene = new Scene(mContentParent, view);
        transitionTo(newScene);
    } else {
        // 没有转场动画,view就是subDecor,ContentParent是decorView中的内容容器。
        // 即subDecor添加到decorView中的内容容器中。
        mContentParent.addView(view, params);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}

简要概括 PhoneWindow#ensureSubDecor做的事情

  • 初始化DecorView,创建是在PhoneWindow中进行的。
  • 根据情况加载subDecor。
  • subDecor添加到DecorView中的内容容器中。
step1.2 LayoutInflater#inflate()

调用inflate()填充页面,把resId布局添加到content容器中

---LayoutInflater.from(mContext).inflate(resId, contentParent);

--> LayoutInflater#inflate(...)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
    return inflate(parser, root, root != null);
}

--> LayoutInflater#inflate(...)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
    ...
    // 返回布局解析器XmlResourceParser,xml转成了对象。
    final XmlResourceParser parser = res.getLayout(resource);
    ...
    // root是ViewGroup即android.R.id.content,继续跟进
    return inflate(parser, root, attachToRoot);
}

--> LayoutInflater#inflate(...)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

        final Context inflaterContext = mContext;
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        Context lastContext = (Context) mConstructorArgs[0];
        mConstructorArgs[0] = inflaterContext;
        View result = root;

        try {
            // Look for the root node.
            // 过滤xml解析器END_DOCUMENT和非START_TAG的事件
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                   type != XmlPullParser.END_DOCUMENT) {
                // Empty
            }
            // 获取标签名称
            final String name = parser.getName();

            // 如果标签名称为merge则直接调用rInflate(...),else逻辑最后也会调用到rInflate(...)方法,当前我们先看else逻辑
            if (TAG_MERGE.equals(name)) {
                ...
                rInflate(parser, root, inflaterContext, attrs, false);
            } else {
                // 标注1.2.1
                // Temp is the root view that was found in the xml
                final View temp = createViewFromTag(root, name, inflaterContext, attrs);
                ...
                    
                // 标注1.2.2
                // Inflate all children under temp against its context.
                rInflateChildren(parser, temp, attrs, true);

                // 标注1.2.3
                // We are supposed to attach all the views we found (int temp)
                // to root. Do that now.
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }

                // 标注1.2.4
                // Decide whether to return the root that was passed in or the
                // top view found in xml.
                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }

        } catch (XmlPullParserException e) {
            ...
        } catch (Exception e) {
            ...
        } finally {
            ...
        }

        return result;
    }
}
标注1.2.1

根据xml中的标签创建对应的View,例如

--> final View temp = createViewFromTag(root, name, inflaterContext, attrs)
--> LayoutInflater#createViewFromTag(...)
private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {
  return createViewFromTag(parent, name, context, attrs, false);
}

--> LayoutInflater#createViewFromTag(...)
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
                     boolean ignoreThemeAttr) {
  ...
  try {
      View view;
      // mFactory2和mFactory是继承Factory,它是创建View的一个工厂,跟进mFactory2.onCreateView(...)源码
      if (mFactory2 != null) {
          view = mFactory2.onCreateView(parent, name, context, attrs);
      } else if (mFactory != null) {
          view = mFactory.onCreateView(name, context, attrs);
      } else {
          view = null;
      }
      ...
      return view;
  } catch (xxx e) {
      ...
  }
}

--> AppCompatDelegateImpl#onCreateView(...)
public View createView(View parent, final String name, @NonNull Context context,
                         @NonNull AttributeSet attrs) {
  if (xxx) {
      if(xxx){
          mAppCompatViewInflater = new AppCompatViewInflater();
      } else {
          Class viewInflaterClass = Class.forName(viewInflaterClassName);
          mAppCompatViewInflater =
              (AppCompatViewInflater) viewInflaterClass.getDeclaredConstructor()
              .newInstance();
      }
  }
  ...
  return mAppCompatViewInflater.createView(parent, name, context, attrs,...);
}

--> AppCompatViewInflater#createView(...)
final View createView(View parent, final String name, @NonNull Context context,
          @NonNull AttributeSet attrs, boolean inheritContext,
          boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
  ...
      View view = null;

      // xml中解析到的标签name,然后根据其名称创建View
      // We need to 'inject' our tint aware Views in place of the standard framework versions
      switch (name) {
          case "TextView":
              // 这里我们省略其他的控件创建,先只看TextView,继续跟进。
              view = createTextView(context, attrs);
              verifyNotNull(view, name);
              break;
          ...
          default:
              // The fallback that allows extending class to take over view inflation
              // for other tags. Note that we don't check that the result is not-null.
              // That allows the custom inflater path to fall back on the default one
              // later in this method.
              view = createView(context, name, attrs);
      }
      return view;
}

--> AppCompatViewInflater#createTextView(...)
@NonNull
protected AppCompatTextView createTextView(Context context, AttributeSet attrs) {
  // 在这里可以看到虽然解析到是TextView标签,并未创建TextView实例,最后是创建了AppCompatTextView实例
  // 这样的设计很好,开发者使用以前的标签,但最后android内部将其转化成增强型的AppCompatTextView。
  // 这样既达到了升级的目的,并且开发者也不用修改xml布局代码。
  return new AppCompatTextView(context, attrs);
}
标注1.2.2

填充所有的子孩子

---> rInflateChildren(parser, temp, attrs, true);

--> LayoutInflater#rInflateChildren(...)
final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
                            boolean finishInflate) throws XmlPullParserException, IOException {
    rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}

--> LayoutInflater#rInflate(...)
void rInflate(XmlPullParser parser, View parent, Context context,
              AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {

    final int depth = parser.getDepth();
    int type;
    boolean pendingRequestFocus = false;

    while (((type = parser.next()) != XmlPullParser.END_TAG ||
            parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {

        if (type != XmlPullParser.START_TAG) {
            continue;
        }

        final String name = parser.getName();

        if (TAG_REQUEST_FOCUS.equals(name)) {
            pendingRequestFocus = true;
            consumeChildElements(parser);
        } else if (TAG_TAG.equals(name)) {
            parseViewTag(parser, parent, attrs);
        } else if (TAG_INCLUDE.equals(name)) {
            if (parser.getDepth() == 0) {
                throw new InflateException("<include /> cannot be the root element");
            }
            parseInclude(parser, context, parent, attrs);
        } else if (TAG_MERGE.equals(name)) {
            throw new InflateException("<merge /> must be the root element");
        } else {
            // 解析xml标签创建对应的View
            final View view = createViewFromTag(parent, name, context, attrs);
            final ViewGroup viewGroup = (ViewGroup) parent;
            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
            // 填充子View,这里可以看到,形成了一个递归,所以尽量少的ViewGroup嵌套ViewGroup,因为这样很容易造成,栈溢问题。
            rInflateChildren(parser, view, attrs, true);
            // view添加到容器中
            viewGroup.addView(view, params);
        }
    }

    if (pendingRequestFocus) {
        parent.restoreDefaultFocus();
    }

    if (finishInflate) {
        parent.onFinishInflate();
    }
}
标注1.2.3

当root != null && attachToRoot附着标志位为true,直接xml解析的view直接添加到root上,在这里就是把布局文件添加到内容容器中

标注1.2.4

若调用LayoutInflater.from(mContext).inflate(resId, null),那么就直接返回解析好的布局View

简要概括LayoutInflater#inflate做的事情

  • LayoutInflater对象把开发者设置的布局,解析成对应的View(牵涉到递归,会导致栈溢出情况),然后添加到content中
  • 当前还没能显示出来,只是建立一套view结构,全部放在了DecorView中,然后把decorView交给WindowManager。

二 onResume()

熟悉Activity启动流程可知,Activity#onResume()是由ActivityThread#handleResumeActivity触发的,所以分析我们从handleResumeActivity(…)开始分析。

---> ActivityThread#handleResumeActivity
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                 String reason) {
    // TODO Push resumeArgs into the activity for consideration
    // step 2.1
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    final Activity a = r.activity;
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow(); // r.window就是PhoneWindow对象
        View decor = r.window.getDecorView(); // decor就是DecorView对象,创建时机在上面分析的 标注1.1.2中
        decor.setVisibility(View.INVISIBLE); 
        ViewManager wm = a.getWindowManager();  // wm就是WindowManagerImpl实例,那么创建的时机是什么时候?,稍后分析
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;

        // step 2.2
        wm.addView(decor, l);
        // step 2.3
        r.activity.makeVisible(); 
    } 
}

WindowManagerImpl的创建时机,先看ViewManager wm = a.getWindowManager(); 
Activity#getWindowManager()
public WindowManager getWindowManager() {
    // mWindowManager的创建的创建时机是什么时候呢?如果了解Activity启动流程,可知Activity#attach()有初始化
    return mWindowManager;
}

Activity#attach(...)
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) {
        ...
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ...
        // 再查看下PhoneWindow.setWindowManager()方法,但在PhoneWindow搜索不到该方法,需追踪到父类Window
        mWindow.setWindowManager(
        (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), // 传入WMS服务
        mToken,...);
        ...
        mWindowManager = mWindow.getWindowManager();
}

Window#setWindowManager()
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
                                 boolean hardwareAccelerated) {
    // 如果外部传入WMS对象为空,则重新获取WMS服务
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    // 继续追查WindowManagerImpl#createLocalWindowManager(this)
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

WindowManagerImpl#createLocalWindowManager(...)
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    // parentWindow就是PhoneWindow对象
    return new WindowManagerImpl(mContext, parentWindow);
}    
    
step2.1 performResumeActivity(…)

ACtivity客户端活动记录

public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
                                                  String reason) {
    final ActivityClientRecord r = mActivities.get(token);
    ...
    if (finalStateRequest) {
        r.hideForNow = false;
        r.activity.mStartedActivity = false;
    }
    try {
        ...
        // 触发Activity#onResume()
        r.activity.performResume(r.startsNotResumed, reason);
        ...
    } catch (Exception e) {
        ...
    }
    return r;
}
step2.2 WindowManagerImpl#addView(…)

往WindowManagerImpl添加decor建立联系

--> wm.addView(decor, l); wm的创建的时机是?
Activity#getWindowManager()
public WindowManager getWindowManager() {
    // mWindowManager的创建的创建时机是什么时候呢?如果了解Activity启动流程,可知Activity#attach()有初始化
    return mWindowManager;
}

Activity#attach(...)
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) {
        ...
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ...
        mMainThread = aThread;
        ...
        mWindow.setWindowManager(
        (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), // 传入WMS服务
        mToken,...);
        ...
        mWindowManager = mWindow.getWindowManager();
}

再查看下PhoneWindow.setWindowManager()方法,但在PhoneWindow搜索不到该方法,需追踪到父类Window
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
                                 boolean hardwareAccelerated) {
    // 如果外部传入WMS对象为空,则重新获取WMS服务
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    // 赋值给mWindowManager
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}


--> WindowManagerImpl#addView(...)
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);// view就是DecorView对象
}

--> WindowMamagerGlobal#addView(...)
public void addView(View view, ViewGroup.LayoutParams params,
                    Display display, Window parentWindow) {
    ViewRootImpl root;
    root = new ViewRootImpl(view.getContext(), display); // 创建ViewRootImpl
    mViews.add(view);// view就是DecorView对象,添加到了View集合中
    mRoots.add(root);// root添加到ViewRootImpl集合中
    root.setView(view, wparams, panelParentView);// ViewRootImpl绑定DecorView
}

ViewRootImpl#setView(...)
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        mView = view; // mView保存DecorView对象,后面在测量布局绘制,会使用mView。
        // 标注2.2.1 
        requestLayout();
        // 标注2.2.2
        mWindowSession.addToDisplay(mWindow,...) // mWindow是ViewRootImpl内部类W
    }
}
标注2.2.1

调用ViewRootImpl#requestLayout()触发界面刷新

ViewRootImpl#requestLayout()
@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        // 检查线程
        checkThread();
        mLayoutRequested = true;
        // 遍历
        scheduleTraversals();
    }
}

--> ViewRootImpl#scheduleTraversals()
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        // 插入一个屏障消息,普通handler消息暂时不会被处理,只有异步消息可以处理。
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // mChoreographer编舞者类,主要用来编排刷新的,通过vy信号会触发,然后再看下mTraversalRunnable的处理
        mChoreographer.postCallback(
            Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        ...
    }
}

--> TraversalRunnable#run()
final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

--> ViewRootImpl#doTraversal()
void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // 移除屏障消息
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        // 处理view的测量布局绘制
        performTraversals();
        ...
    }
}

--> ViewRootImpl#performTraversals()
private void performTraversals() {
    // 拿到windowSession调用relayout(,mSurface);
    // mSurface有buff就可以绘制了,申请Surface
    relayoutWindow(prams,..)
    ...
    // 接下来依次执行View#measure(...) , DecorView#onMeasure(...)
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 
    ...
    // 接下来依次执行View#layout(...) , DecorView#onLayout(...)
    performLayout(lp, mWidth, mHeight);
    ...
    // 接下来依次执行View#draw(...) , DecorView#onDraw(...)
    performDraw();
} 
标注2.2.2

这里非常非常非常重要,简而言之,与WMS建立关系,向WMS申请surfaece。

mWindowSession.addToDisplay(mWindow,…)中的mWindowSession是wms.openSession(…)返回的一个binder对象,用来与应用通信的,详细源码如下。

ViewRootImpl构造函数
public ViewRootImpl(Context context, Display display) {
    ...
    mWindowSession = WindowManagerGlobal.getWindowSession();
    ...
}

public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            // 返回WMS
            IWindowManager windowManager = getWindowManagerService();
            // 继续跟进WMS#openSession(...)
            sWindowSession = windowManager.openSession(
                new IWindowSessionCallback.Stub() {
                    @Override
                    public void onAnimatorScaleChanged(float scale) {
                        ValueAnimator.setDurationScale(scale);
                    }
                },
                ...);
        }
        // 返回Session对象
        return sWindowSession;
    }
}

WindowManagerService#openSession(...)
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
                                  IInputContext inputContext) {
    if (client == null) throw new IllegalArgumentException("null client");
    if (inputContext == null) throw new IllegalArgumentException("null inputContext");
    Session session = new Session(this, callback, client, inputContext);
    return session;
}

mWindowSession.addToDisplay(mWindow,…)中的mWindow是ViewRootImpl的静态内部对象,把应用端W对象,注册到到AMS中组成双向调用,源码如下。

public ViewRootImpl(Context context, Display display) {
    mWindow = new W(this);
}

// W也是一个binder
static class W extends IWindow.Stub {
    private final WeakReference<ViewRootImpl> mViewAncestor;
    private final IWindowSession mWindowSession;

    W(ViewRootImpl viewAncestor) {
        mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
        mWindowSession = viewAncestor.mWindowSession;
    }
}

现在继续查看addToDisplay方法,mWindowSession前面分析到,就是Session对象,那么直接查看源码

Session#addToDisplay(...)
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
                            int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
                            Rect outStableInsets, Rect outOutsets,
                            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    // 直接调用AMS的addWindow方法,就是创建对应的window对象
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
                              outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}

ActivityManagerService#addWindow(...)
public int addWindow(Session session, IWindow client, int seq,
                     LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
                     Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                     DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    ...
    这里暂时就不再分析,以后再详细说明
}

调用addToDisplay即是在AMS创建window相关的对象,统一管理所有window的显示层级,大小,位置

WMS主要是给应用端分配Surface,并掌管Surface显示顺序,大小,位置,不关注应用的中的绘制,但应用端在surface绘制完后,surfaceflinger按照WMS提供Surface信息,依次绘制合成,最后写到屏幕的缓存区,显示出来。

WMS作用

1 分配surface

2掌控surface显示顺序大小位置

3控制窗口动画

4 输入事件分发

step2.3 Activity#makeVisible

让界面显示

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        // 根view添加到window中
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    // 显示界面,所以为什么说是在activity#onResume()后才显示界面
    mDecor.setVisibility(View.VISIBLE);
}

三 参考

https://www.cnblogs.com/huansky/p/11911549.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值