美文网首页
Window DecorView ViewRootImpl的关系

Window DecorView ViewRootImpl的关系

作者: jxiang112 | 来源:发表于2022-04-16 21:45 被阅读0次

定义

ContextImpl

启动activity流程中,在创建Activity之前会创建activity关联的上下文实例contextimpl,其内部提供访问资源、服务等等诸多接口,同时注册并缓存了诸多服务,是用过SystemServiceRegistry注册的,其中注册了WINDOW_SERVICE关联的WindowManager的实现类WindowManagerImpl等

Window

每个Activity都会绑定一个窗口window,其实现类是PhoneWindow,它是WindowManager的跟容器

DecorView

DecorView是View视图树的根布局,它继承了FrameLayout,包含三大部分的子View:LineLayout(Activity视图内容容器,其包含两部分actionBar和一个id为R.id.content的FrameLayout)、navigationBarBackground(导航栏)、statusBarBackround(状态栏)

ViewRootImpl

ViewRootImpl是View的根,但它不是View视图树的一部分,它是Window和DecorView的交互桥梁,用来控制View测量和绘制,同时它持有WindowSession通过Binder与WMS通信,实现如事件分发

关系流程

Activity的attch——》创建PhoneWindow,同时设置WindowManager,将PhoneWindow作为WindowManagerImpl的window——》setContentView——》进入PhoneView创建DecorView,并将加载activity的视图到decorView中——》ActivityThread的handleResumeActivity将decorView设置为不可见,创建ViewRootImpl,并通过ViewRootImpl进行视图测量和绘制

attach

创建创建PhoneWindow,同时设置WindowManager,将PhoneWindow作为WindowManagerImpl的window

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);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
      //......
      mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
      //......
}

//Window.setWindowManager
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);
        }
        //此wm是WindowManager的实现类WindowManagerImpl
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        //此parentWindow是PhoneWindow,将PhoneWindow作为WindowManagerImpl的父window
        mParentWindow = parentWindow;
    }

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

Activity的setContentView会调用PhoneWindow的setContentView:

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

我们接着看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创建DecorView
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        //.....
        //加载xml转为视图加载到DecorView视图树中
            mLayoutInflater.inflate(layoutResID, mContentParent);
        //.....
    }

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            //调用generateDecor方法创建DecorVIew
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            //如果DecorView内容为空,则调用generateLayout生成DecorVIew的布局内容
            mContentParent = generateLayout(mDecor);
        //......
 }
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
        //.....
          //创建decorView
        return new DecorView(context, featureId, this, getAttributes());
}
protected ViewGroup generateLayout(DecorView decor) {
    // Apply data from current theme.
    
    //.......应用设置activity的样式,这里省略.....
    mDecor.startChanging();
    //layoutResource是DecorView内容布局xml文件id
    //onResourcesLoaded将布局文件加载到DecorView中
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
    //ID_ANDROID_CONTENT = com.android.internal.R.id.content
    //将id为content的FrameLayout作为Activity布局视图的容器
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    //.......
}

generateLayout主要是设置activity的样式,并根据样式选择DecorView的内容布局xml文件id,接着调用DecorVIew的onResourcesLoaded方法添加内容布局到DecorView中,我们接着看DecorView的onResourcesLoaded方法:

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
       //......
        //加载布局文件
        final View root = inflater.inflate(layoutResource, null);
        if (mDecorCaptionView != null) {
            if (mDecorCaptionView.getParent() == null) {
                addView(mDecorCaptionView,
                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
            }
             //添加布局到DecorView中
            mDecorCaptionView.addView(root,
                    new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        } else {

            // Put it below the color views.
            //添加布局到DecorView中
            addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
        mContentRoot = (ViewGroup) root;
        initializeElevation();
    }

setContentView主要做的事:

  • 使用PhoneWindow创建DecorView
  • 设置activity样式,本根据样式选择DecorView的内容布局xml文件id
  • 加载DecorView的布局文件并添加到DecorView中
  • 使用id为content的FragmentLayout作为activity的布局视图的容器

handleResumeActivity

ActivityThread的handleResumeActivity依次调用performResumeActivity、将DecorView设置为不可见、创建ViewRootImpl、调用ViewRootImpl的setView对DecorView进行测量和绘制:

@Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
       //......
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        //......
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
       if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
        //......
        if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible();
        }
}

handleResumeActivity中wm.addView是进行创建ViewRootImpl和调用ViewRootImpl的关键,其中wm是WindowManagerImpl,我们继续看下WindowManagerImpl的addView方法:

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

WindowManagerImpl的addView又调用mGlobal的addView,其中WindowManagerGlobal的实例,我们继续进入WindowManagerGlobal的addView方法:

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
    //......
    synchronized (mLock) {
        //......
        //创建ViewRootImpl
        root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
          
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                //调用ViewRootImpl的setView对DecorView进行测量和绘制操作
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
    }
    //......
}

WindowManagerGlobal的addView中先创建ViewRootImpl,接着调用ViewRootImpl的setView对DecorView进行测量和绘制操作(测量和绘制流程见:Android View绘制流程

我们回到ActivityThread的handleResumeActivity的makeVisible部分,调用的是activity的makeVisible方法,我们接着看activity的makeVisible方法:

void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        //将DecorView设置为可见
        mDecor.setVisibility(View.VISIBLE);
    }

相关文章

网友评论

      本文标题:Window DecorView ViewRootImpl的关系

      本文链接:https://www.haomeiwen.com/subject/ddwhertx.html