您的位置:首页 > 移动开发 > Android开发

从源码分析View绘制流程

2017-02-17 11:32 537 查看
先看一张view绘制流程的时序图



Activity加载显示基本流程



研究入口:Activity.setContentView(layoutId);

public void setContentView(@LayoutRes int layoutResID) {

getWindow().setContentView(layoutResID);

initWindowDecorActionBar();

}

[/code]

发现调用了getWindow()方法,该方法获取的Window对象实例,但是Window是抽象类,其真正的实现类是PhoneWindow.

@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();

} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

mContentParent.removeAllViews();

}


if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,

        getContext());

transitionTo(newScene);

} else {

mLayoutInflater.inflate(layoutResID, mContentParent);

}

mContentParent.requestApplyInsets();

final Callback cb = getCallback();

if (cb != null && !isDestroyed()) {

cb.onContentChanged();

}

}

[/code]

1.初次进入会进入代码6-7行,查看方法installDecor(), 这个方法非常核心


private void installDecor() {

if (mDecor == null) {

mDecor = generateDecor();

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

mDecor.setIsRootNamespace(true);

if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {

    mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);

}

}

if (mContentParent == null) {

mContentParent = generateLayout(mDecor);


....


[/code]

代码4行,generateDecor()->生成DecorView,界面根布局:DecorView是PhoneWindow的内部类,继承自FrameLayout.

protected DecorView generateDecor() {

return new DecorView(getContext(), -1);

}

[/code]

代码14行,在decorview界面上,添加界面

protected ViewGroup generateLayout(DecorView decor) {

  ........//actionbar的一些设置

  // System.out.println("Title!");

} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {

layoutResource = R.layout.screen_simple_overlay_action_mode;

} else {

// Embedded, so no decoration is needed.

layoutResource = R.layout.screen_simple;

// System.out.println("Simple!");

}


mDecor.startChanging();


View in = mLayoutInflater.inflate(layoutResource, null);

decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

mContentRoot = (ViewGroup) in;


ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);


  ........//其他的一些操作
mDecor.finishChanging();

return contentParent;


[/code]

如果ActionBar没有特殊要求,layoutResource一般会调用系统的xml布局文件R.layout.screen_simple.在这个布局中就有一个id为content的FrameLayout的控件,就是generateLayout(decoreview)方法返回得到的mContentParent.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:fitsSystemWindows="true"

android:orientation="vertical">

<ViewStub android:id="@+id/action_mode_bar_stub"

  android:inflatedId="@+id/action_mode_bar"

  android:layout="@layout/action_mode_bar"

  android:layout_width="match_parent"

  android:layout_height="wrap_content" />

<FrameLayout

android:id="@android:id/content"

     android:layout_width="match_parent"

     android:layout_height="match_parent"

android:foregroundInsidePadding="false"

android:foregroundGravity="fill_horizontal|top"

android:foreground="?android:attr/windowContentOverlay" />

</LinearLayout>


[/code]

setContentView(layoutId)方法第17行代码,是将我们传入的xml布局文件添加到mContentParent中。

而view绘制入口则是mDecor.finishChanging()->这个方法里面最终会调用requestLayout()方法

public void finishChanging() {

mChanging = false;

drawableChanged();

}

[/code]

private void drawableChanged() {

if (mChanging) {

    return;

}


setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top

        + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,

        mFramePadding.bottom + mBackgroundPadding.bottom);

requestLayout();

invalidate();



[/code]

因为DecorView继承自 FrameLayout->最后会调用View方法的requestLayout()方法

@CallSuper

public void requestLayout() {

if (mMeasureCache != null) mMeasureCache.clear();


if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {

// Only trigger request-during-layout logic if this is the view requesting it,

// not the views in its parent hierarchy

ViewRootImpl viewRoot = getViewRootImpl();

if (viewRoot != null && viewRoot.isInLayout()) {

    if (!viewRoot.requestLayoutDuringLayout(this)) {

        return;

}

}

mAttachInfo.mViewRequestingLayout = this;

}


mPrivateFlags |= PFLAG_FORCE_LAYOUT;

mPrivateFlags |= PFLAG_INVALIDATED;


if (mParent != null && !mParent.isLayoutRequested()) {

mParent.requestLayout();

}

if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {

mAttachInfo.mViewRequestingLayout = null;

}

}

[/code]

在requestlayout()方法中,会到ViewRootImpl这个类中去进行绘制处理

final class TraversalRunnable implements Runnable {

    @Override

public void run() {

doTraversal();

}

}

[/code]
void doTraversal() {

if (mTraversalScheduled) {

mTraversalScheduled = false;

mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);


if (mProfile) {

    Debug.startMethodTracing("ViewAncestor");

}


performTraversals();


if (mProfile) {

    Debug.stopMethodTracing();

    mProfile = false;

}

}

}

[/code]

最终在performTraversals()方法中会调用测量meaure,摆放layout,绘制draw方法

private void performTraversals() {


// Ask host how big it wants to be

performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);


performLayout(lp, desiredWindowWidth, desiredWindowHeight);


performDraw();


[/code]

performMeasure()测量方法->最终调用的是view的measure方法->onMeasure()

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);

}

}

[/code]

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {

boolean optical = isLayoutModeOptical(this);

if (optical != isLayoutModeOptical(mParent)) {

Insets insets = getOpticalInsets();

int oWidth  = insets.left + insets.right;

int oHeight = insets.top  + insets.bottom;

widthMeasureSpec  = MeasureSpec.adjust(widthMeasureSpec,  optical ? -oWidth  : oWidth);

heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);

}


// Suppress sign extension for the low bytes

long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;

if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);


if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||

    widthMeasureSpec != mOldWidthMeasureSpec ||

    heightMeasureSpec != mOldHeightMeasureSpec) {


// first clears the measured dimension flag

mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;


resolveRtlPropertiesIfNeeded();


int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :

        mMeasureCache.indexOfKey(key);

if (cacheIndex < 0 || sIgnoreMeasureCache) {

    // measure ourselves, this should set the measured dimension flag back

    onMeasure(widthMeasureSpec, heightMeasureSpec);

    mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;

} else {

    long value = mMeasureCache.valueAt(cacheIndex);

    // Casting a long to int drops the high 32 bits, no mask needed

    setMeasuredDimensionRaw((int) (value >> 32), (int) value);

    mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;

}


// flag not set, setMeasuredDimension() was not invoked, we raise

// an exception to warn the developer

if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {

    throw new IllegalStateException("View with id " + getId() + ": "

+ getClass().getName() + "#onMeasure() did not set the"

+ " measured dimension by calling"

+ " setMeasuredDimension()");

}


mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;

}


mOldWidthMeasureSpec = widthMeasureSpec;

mOldHeightMeasureSpec = heightMeasureSpec;


mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |

    (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension

}

[/code]

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),

    getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));

}

[/code]

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {

boolean optical = isLayoutModeOptical(this);

if (optical != isLayoutModeOptical(mParent)) {

Insets insets = getOpticalInsets();

int opticalWidth  = insets.left + insets.right;

int opticalHeight = insets.top  + insets.bottom;


measuredWidth  += optical ? opticalWidth  : -opticalWidth;

measuredHeight += optical ? opticalHeight : -opticalHeight;

}

setMeasuredDimensionRaw(measuredWidth, measuredHeight);

}


[/code]

performLayout()控件摆放->最后调用的是 view的layout方法

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,

int desiredWindowHeight) {

mLayoutRequested = false;

mScrollMayChange = true;

mInLayout = true;


final View host = mView;

if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {

Log.v(TAG, "Laying out " + host + " to (" +

        host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");

}


Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");

try {

host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());

[/code]

performDraw()绘制方法->绘制分发

private void performDraw() {

if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {

return;

}


final boolean fullRedrawNeeded = mFullRedrawNeeded;

mFullRedrawNeeded = false;


mIsDrawing = true;

Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");

try {

draw(fullRedrawNeeded);

} finally {

mIsDrawing = false;

Trace.traceEnd(Trace.TRACE_TAG_VIEW);

}


// For whatever reason we didn't create a HardwareRenderer, end any

// hardware animations that are now dangling

if (mAttachInfo.mPendingAnimatingRenderNodes != null) {

final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();

for (int i = 0; i < count; i++) {

    mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();

}

mAttachInfo.mPendingAnimatingRenderNodes.clear();

}


if (mReportNextDraw) {

mReportNextDraw = false;

if (mAttachInfo.mHardwareRenderer != null) {

    mAttachInfo.mHardwareRenderer.fence();

}


if (LOCAL_LOGV) {

    Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());

}

if (mSurfaceHolder != null && mSurface.isValid()) {

    mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);

    SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();

    if (callbacks != null) {

        for (SurfaceHolder.Callback c : callbacks) {

if (c instanceof SurfaceHolder.Callback2) {

    ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(

mSurfaceHolder);

}

}

}

}

try {

    mWindowSession.finishDrawing(mWindow);

} catch (RemoteException e) {

}

}

}

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android view绘制