Android高级-View的绘制流程

上文创建好了DecorView,并通过setContentView方法将需要展示的view添加到基础布局中去,现在开始绘制View------>绘制完成------->展示

 View的绘制流程 

   分为三步                       

        

一  绘制入口  

  ActivityThread就是我们常说的主线程或UI线程,ActivityThread的main方法是整个APP的入口

  (附上ActivityThread理解及启动过程:https://blog.csdn.net/hzwailll/article/details/85339714)

  找到handleMessage()方法,该方法是所有activity调用都会触发的,在里面会调用handlerResumeActivity()方法。最后跟踪到 windowManagerImpl ,找到addView()方法

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

   会调用到mGlobal的addView()方法,进入源码查看

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    //省略...
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if (parentWindow != null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } else {
        // If there's no parent, then hardware acceleration for this view is
        // set from the application's hardware acceleration setting.
        final Context context = view.getContext();
        if (context != null
                && (context.getApplicationInfo().flags
                        & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }
    ViewRootImpl root;
    View panelParentView = null;
    //省略......
       root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);//给view设置参数
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);

        // do this last because it fires off messages to start doing things
        try {
            root.setView(view, wparams, panelParentView);//将三个参数关联 
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throw e;
        }
    }
}

二  绘制的类和入口

然后追踪到root.setView方法。

/**
 * We have one child
 */
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            mAttachInfo.mDisplayState = mDisplay.getState();
            mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
            mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
            mFallbackEventHandler.setView(view);
            mWindowAttributes.copyFrom(attrs);
            if (mWindowAttributes.packageName == null) {
                mWindowAttributes.packageName = mBasePackageName;
            }
            attrs = mWindowAttributes;
            setTag();
            if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
                    & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
                    && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
                Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
            }
            // Keep track of the actual window flags supplied by the client.
            mClientWindowLayoutFlags = attrs.flags;
            setAccessibilityFocus(null, null);
            if (view instanceof RootViewSurfaceTaker) {
                mSurfaceHolderCallback =
                        ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                if (mSurfaceHolderCallback != null) {
                    mSurfaceHolder = new TakenSurfaceHolder();
                    mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                    mSurfaceHolder.addCallback(mSurfaceHolderCallback);
                }
            }
            // Compute surface insets required to draw at specified Z value.
            // TODO: Use real shadow insets for a constant max Z.
            if (!attrs.hasManualSurfaceInsets) {
                attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
            }

            CompatibilityInfo compatibilityInfo =
                    mDisplay.getDisplayAdjustments().getCompatibilityInfo();
            mTranslator = compatibilityInfo.getTranslator();

            // If the application owns the surface, don't enable hardware acceleration
            if (mSurfaceHolder == null) {
                enableHardwareAcceleration(attrs);
            }

            boolean restore = false;
            if (mTranslator != null) {
                mSurface.setCompatibilityTranslator(mTranslator);
                restore = true;
                attrs.backup();
                mTranslator.translateWindowLayout(attrs);
            }
            if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);

            if (!compatibilityInfo.supportsScreen()) {
                attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
                mLastInCompatMode = true;
            }

            mSoftInputMode = attrs.softInputMode;
            mWindowAttributesChanged = true;
            mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
            mAttachInfo.mRootView = view;
            mAttachInfo.mScalingRequired = mTranslator != null;
            mAttachInfo.mApplicationScale =
                    mTranslator == null ? 1.0f : mTranslator.applicationScale;
            if (panelParentView != null) {
                mAttachInfo.mPanelParentWindowToken
                        = panelParentView.getApplicationWindowToken();
            }
            mAdded = true;
            int res; /* = WindowManagerImpl.ADD_OKAY; */

            // Schedule the first layout -before- adding to the window
            // manager, to make sure we do the relayout before receiving
            // any other events from the system.
            requestLayout();  
            //省略....

        }
    }
}

      下面总结一下在ViewRootImpl 的requestLayout方法之前都做了哪些操作

        

    然后我们继续查看源码,,从ViewRootImpl.requestLayout()的方法进入,

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }

 继续

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
      //省略...
    }
}

mTraversalRunnable 我们注意到这个线程

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}
//省略....

继续追踪这个方法

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }
        performTraversals();//上下都是调试信息
        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

 继续追踪

三  View绘制三大步骤

private void performTraversals() {
  
//...
  performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
//...     
  performLayout(lp, mWidth, mHeight);
//...
 performDraw();

}

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值