View显示流程-View draw的准备工作

前言:不断反思,不断进步,不断学习!
不知怎么的,觉得自己的语言组织不起来,逻辑性不强,所以就多学学别人的风格,背诵。
View的展示是从Activity的setContentView方法开始,以此为入口,以Android6.0为source-code,分析看看。

1、

        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
...
 /**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     *
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
    ...
 }

添加所有的topview到Activity, getWindow().setContentView(layoutResID)是怎么实现的呢?是Window.java的一个抽象方法
2、

    public abstract void setContentView(View view);

最终的实现类是会进入的PhoneWindow.java的setContentView方法 ,有很多setContentView的重载。
3、

    // 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;
    public void setContentView(View view, ViewGroup.LayoutParams params) {  
            if (mContentParent == null) {  
                installDecor();  
            } else {  
                mContentParent.removeAllViews();  
            }  
            mContentParent.addView(view, params);  
           ....  
        }  

mContentParent是一个ViewGroup对象,也是Activity内容部分的根View,他的创建依赖installDecor()

4、

   private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            ......
            }
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
         ......    
        }

installDecor在创建DecorView(顶级View,是FrameLayout的子类,是整个Activity的框架)的同时,然后通过generateLayout(mDecor)来创建ViewGroup mContentParent ,与其说是创建,不如说是获取,是从顶级View实例化的xml布局中获取生成的。
5、

    protected ViewGroup generateLayout(DecorView decor) {  
            .......  
            View in = mLayoutInflater.inflate(layoutResource, null);  
            decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
            ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  
            .......  
            return contentParent;  
    }  

回到4中,将我们需要加入的view加入到contentParent,这样我们要展示的View就准备好了,但是还没有开始绘制。
之后,随着Activity的onCreate方法执行完毕,view加载结束后,AMS会调用ActivityThread.handleResumeActivity方法
6、

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,  
                boolean reallyResume) {  
           .......  
           ActivityClientRecord r = performResumeActivity(token, clearHide);  
           .......  
           final Activity a = r.activity;   //获取activity对象  
           .......  
           decor.setVisibility(View.INVISIBLE);    //显示decor  
           ViewManager wm = a.getWindowManager();  
           WindowManager.LayoutParams l = r.window.getAttributes();  
           a.mDecor = decor;  
           l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;  
           l.softInputMode |= forwardBit;  
           if (a.mVisibleFromClient) {  
                 a.mWindowAdded = true;  
                  wm.addView(decor, l);     //加载了我们的View  
            }  
            .......  
    }  

这里最重要的代码就是wm.addView(decor, l);但是这里要先说一下wm,看上述代码可知只是一个ViewManager类型,实际上是一个WindowManager(实现了ViewManager接口)。他通过activity的getWindowManager()获得,获得的WindowManager对象最初来自于Window类的getWindowManager()方法,由setWindowManager()创建。
7、

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

这里可以看到,首先我们通过mContext对象获取系统的WindowManagerService。然后通过createLocalWindowManager方法复制了一份。所以说对于WindowManagerService对象,每一个Activity程序都会有一个自己的mWindowManager,回到 wm.addView(decor, l)方法
这个方法的实现在WindowManagerImpl里面,发现他只是一个代理,这个方法最终交给了WindowManagerGlobal类的一个单例来执行。
8、

    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();   //单例对象  
    ...............
        private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();

    ...............  
         public void addView(View view, ViewGroup.LayoutParams params,  
            Display display, Window parentWindow) {  
             .........  
            ViewRootImpl root;  
             .........  
             root = new ViewRootImpl(view.getContext(), display);  
             view.setLayoutParams(wparams);  
             mViews.add(view);  
             mRoots.add(root);  
             .........  
             root.setView(view, wparams, panelParentView);//后续会关注于ViewRoot的实现  
             .........  
    }  
    }  

这里我们首次看到了ViewRoot,这是非常重要的类。在ViewRoot的构造函数中可见,
9、

/**
 * The top of a view hierarchy, implementing the needed protocol between View
 * and the WindowManager.  This is for the most part an internal implementation
 * detail of {@link WindowManagerGlobal}.
 *
public ViewRootImpl(Context context, Display display) {  
        .......  
        mWindowSession = WindowManagerGlobal.getWindowSession();  
        ......  
}  

Session是在WMS中直接创建的,如名字一样,这是一个WMS与ViewRoot的一个会话,由此ViewRoot的功能就非常清楚:是View与WMS通信的桥梁,在ViewRoot中使用WMS。我们了解了ViewRoot的功能,让我们看看他是如何执行的。我们回到WindowManagerImpl的addView()。ViewRoot使用setView方法将我们需要显示View放入ViewRoot内进行操作。
10、

  public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
                ..........  
                requestLayout();  
                ..........  
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,  
                            getHostVisibility(), mDisplay.getDisplayId(),  
                            mAttachInfo.mContentInsets, mInputChannel);  
                .........  
}  

我靠,才知道自定义控件使用到的requestLayout、invalidate都是这个类的,有必要好好研究一下。都是和绘制相关的,这里还是先关注于之前的准备工作
11、

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,  
            int viewVisibility, int displayId, Rect outContentInsets,  
            InputChannel outInputChannel) {  
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,  
                outContentInsets, outInputChannel);  
    } 

这里代理调用了mService的addWindow()方法,其中传入的参数window是ViewRoot内的一个内部类通过binder机制放入到WMS中用于WMS反向调用ViewRoot,即与Session相反。这样ViewRoot与WMS建立了双向链接。这时,WMS看看addWindow()方法最终会调用到Session的一个方法

12、


    void windowAddedLocked() {  
       ........  
       mSurfaceSession = new SurfaceSession();  
       ........  
       mService.mSessions.add(this);  
    }  

最终SurfaceSession被放入了Service的HashSet集合里面,
,SurfaceSession就是WMS与SurfaceFlinger的通信桥梁,SurfaceFlinger是用来绘制surface的一个服务,至此Activity的启动消息被执行完成,但是我们还是没有获取到画布,进入performTraversals()方法,有这段代码

13、

                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

14、实现:

 // These can be accessed by any thread, must be protected with a lock.
    // Surface can never be reassigned or cleared (use Surface.clear()).
......
 int relayoutResult = mWindowSession.relayout(
                mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
                mSurface);

就是讲mSurface传入了Session的方法中。mSurface是ViewRoot自己建立的一个Surface对象,但是是个空构造函数没什么意义。这里传入Session就是要利用WMS充实这个Surface对象,这个Surface就是我们要绘制的屏幕。在Session中,他直接把Surface对象传入了mService即WMS对象中。
15、

public int relayout(IWindow window, ..., Surface outSurface) {  
    ......  
    int res = mService.relayoutWindow(this, window, ..., outSurface);  
   ....  
}

这里的outSurface就是从客户端ViewRoot中一步步传入WMS内的Surface对象了。下面来开WMS对Surface对象的处理过程,
已经在java层面上看到了surface的创建,但是ViewRoot的创建(只是简单实例化一个对象,没有意义),SurfaceFlinger创建真正的Surface,WMS获得它。至于Surface怎样传回ViewRoot,还有其他对它的一系列处理,其中大量的代码是在native函数中进行的,这里先不研究native的C++函数。我们优先搞定上层处理。所以我们回到ViewRoot中继续看View的创建于绘制流程。
在performTraversals方法中看看绘制流程,最终看到canvas

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值