zoukankan      html  css  js  c++  java
  • android之View绘制到窗口上的过程

    以前在研究自定义空间的时候,查看过View和ViewGroup绘制的流程的。只是定性的知道会经过onMeasure—onLayout—onDraw这些流程。上一篇Android视图加载到窗口的过程分析分析了视图加载到窗口的过程。主要就是一系列的addView操作,这篇就从addView方法开始看看View是如何绘制到窗口上的。

    ActivityThread#handleResumeActivity方法

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
                boolean reallyResume) {
    ……
    ActivityClientRecord r = performResumeActivity(token, clearHide);
    	……
    if (r.window == null && !a.mFinished && willBeVisible) {
                    r.window = r.activity.getWindow();
                    View decor = r.window.getDecorView();//前面分析过,这个是Window对象所维护的装饰窗口,最顶层的窗口
                    decor.setVisibility(View.INVISIBLE);
                    ViewManager wm = a.getWindowManager();//获取WindowManager,继承自ViewManager,不可实例化,是个接口
                    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);// 通过WindowManager添加到窗口
                    }
    	……
    }

    可以看到最顶层的装饰窗口在activity resume的时候通过windowManager#addView方法添加。

    WindowManagerImpl# addView

    public void addView(View view, ViewGroup.LayoutParams params) {
            mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
    
        public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
    
            ViewRootImpl root;
            View panelParentView = null;
    		......
                root = new ViewRootImpl(view.getContext(), display); // 创建一个ViewRoot对象
    
                view.setLayoutParams(wparams);
    
                if (mViews == null) {
                    index = 1;
                    mViews = new View[1];
                    mRoots = new ViewRootImpl[1];
                    mParams = new WindowManager.LayoutParams[1];
                } else {
                    index = mViews.length + 1;
                    Object[] old = mViews;
                    mViews = new View[index]; 
                    System.arraycopy(old, 0, mViews, 0, index-1);
                    old = mRoots;
                    mRoots = new ViewRootImpl[index];
                    System.arraycopy(old, 0, mRoots, 0, index-1);
                    old = mParams;
                    mParams = new WindowManager.LayoutParams[index];
                    System.arraycopy(old, 0, mParams, 0, index-1);
                }
                index--;
    
                mViews[index] = view;
                mRoots[index] = root;// 将view和ViewRootImp关联起来  ViewRootImp是链接View和WindowManagerService的桥梁
                mParams[index] = wparams;
            }
            try {
                root.setView(view, wparams, panelParentView);// 调用ViewRoot的setView方法
            } 
    		......
        }

    setView:

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
    	requestLayout(); // 请求UI开始绘制重新绘制View树
    	......
            try {
               mOrigWindowType = mWindowAttributes.type;
               mAttachInfo.mRecomputeGlobalAttributes = true;
               collectViewAttributes();
    	// 通知WindowManagerService添加一个窗口  会调用到addWindow方法
               res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                         getHostVisibility(), mDisplay.getDisplayId(),
                         mAttachInfo.mContentInsets, mInputChannel);
            }
    }
    

    两种情况会导致调用到requestLayout,改变视图显示属性,比如setVisibility,是直接或者间接调用该函数。

    @Override
        public void requestLayout() {
            checkThread();// 本次调用是否是在UI线程调用的。
            mLayoutRequested = true;
            scheduleTraversals();
        }
    
        void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
    //分发一个异步消息,处理函数中调用performTraversals()对View进行重新遍历。
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);// mTraversalRunnable是一个Runnable对象
                scheduleConsumeBatchedInput();
            }
        }
    
    	final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
    
    	    final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                doTraversal();//执行doTraversal()
            }
    }
    
    	void doTraversal() {
            if (mTraversalScheduled) {
                mTraversalScheduled = false;
                mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
    	……
                try {
                    performTraversals();
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
    		……
            }
    }
    

    View树遍历的核心函数  measure—layout--draw

    private void performTraversals() {
    	......
        // Ask host how big it wants to be
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    	......
    performLayout();
    ……
    performDraw();
    ……
         mIsInTraversal = false;
    }
    

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
            try {
                mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }

    mView.measure(childWidthMeasureSpec,childHeightMeasureSpec);就执行到了熟悉onMeasure(childWidthMeasureSpec,childHeightMeasureSpec);里面。

  • 相关阅读:
    LINQ体验(11)——LINQ to SQL语句之Null语义和String/DateTime方法
    C#常用正则表达式
    oracle 体系结构解析
    Cloudera Manager5安装总结遇到问题及解决办法
    向CDH5集群中添加新的主机节点
    ZeroCopyLiteralByteString cannot access superclass
    如何杀掉当前正在执行的hadoop任务
    Mapreduce读取Hbase表,写数据到多个Hbase表中
    Mapreduce读取Hbase表,写数据到一个Hbase表中
    HUE 安装
  • 原文地址:https://www.cnblogs.com/qhyuan1992/p/5385330.html
Copyright © 2011-2022 走看看