Android_窗口绘制相关流程

2017-04-23  本文已影响60人  冉桓彬

看到setContentView时, 感觉又要把Activity的启动流程看一遍, 然后又要继续往上看, 不知道何时才能正式进入窗口绘制流程, 下面先把需要做的准备工作记录下来:

1、Windows.java->Callback.class;

1、先从ActivityThread入手:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...
    Activity a = performLaunchActivity(r, customIntent);
    ...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    }
    ...
    if (activity != null) {
        Context appContext = createBaseContextForActivity(r, activity);
        ...
        Window window = null;
        activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
    ...
    }
}
1、ClassLoader加载对应的Activity.class文件
2、createBaseContextForActivity(r, activity);
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
    ...
    ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token, displayId, r.overrideConfig);
    appContext.setOuterContext(activity);
    Context baseContext = appContext;
    ...
    return baseContext;
}
3、activity.attach():

2、Activity.java

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) {
        attachBaseContext(context);
        mWindow = new PhoneWindow(this, window);
        mWindow.setCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        mInstrumentation = instr;
        mToken = token;
        mActivityInfo = info;
        mParent = parent;
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
    }
public void setCallback(Callback callback) {
    mCallback = callback;
}
public interface Callback {
    ...
    public boolean dispatchTouchEvent(MotionEvent event);
    public void onWindowFocusChanged(boolean hasFocus);
    ...
}

从上面代码可以试着分析一波WindowManager, ViewManager, WindowManagerImpl, PhoneWindow, Window的关系

public class PhoneWindow extends Window{...}
public abstract class Window{...}
public final class WindowManagerImpl implements WindowManager{...}
public interface WindowManager extends ViewManager {...}
public interface ViewManager{...}
Window mWindow = new PhoneWindow(this, window);
public PhoneWindow(Context context) {
    super(context);
    mLayoutInflater = LayoutInflater.from(context);
}
public PhoneWindow(Context context, Window preservedWindow) {
    this(context);
}

mWindow.setWindowManager(
           (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), 
            mToken, 
            mComponent.flattenToString(), 
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
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);
}
private WindowManager mWindowManager;
private WindowManagerImpl(Context context, Window parentWindow) {
      mContext = context;
      mParentWindow = parentWindow;
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
      return new WindowManagerImpl(mContext, parentWindow);
}
private final Window mParentWindow;
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    ...
}
public class Instrumentation {
      public void callActivityOnCreate(Activity activity, Bundle icicle) {
          prePerformCreate(activity);
          activity.performCreate(icicle);
          postPerformCreate(activity);
      }
}
class->Instrumentation->
public void callActivityOnCreate(Activity activity, Bundle icicle) {
      prePerformCreate(activity);
      activity.performCreate(icicle);
      postPerformCreate(activity);
}
class->Activity->
final void performCreate(Bundle icicle) {
      restoreHasCurrentPermissionRequest(icicle);
      onCreate(icicle);
      mActivityTransitionState.readState(icicle);
      performCreateCommon();
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
      if (mLastNonConfigurationInstances != null) {
          mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
      }
      if (savedInstanceState != null) {
          mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
      }
      mFragments.dispatchCreate();
}

**onCreate()方法被调用了, 我们通常在onCreate()里面调用setContentView()方法对窗口进行绘制;

3、setContentView:

class Activity->
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}
public Window getWindow() {
    return mWindow;
}
class PhoneWindow->
@Override
public void setContentView(int layoutResID) {
      if (mContentParent == null) {
          installDecor();
      }
}

第一次进入onCreate方法调用setContentView方法时, mContentParent=null; 切入到installDecor方法中

class PhoneWindow->
private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor(-1);
    } 
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
    }
}

此时mDecor = null; 切入到generateDecor(-1)方法

class PhoneWindow->
protected DecorView generateDecor(int featureId) {
    return new DecorView(context, featureId, this, getAttributes());
}
class DecorView->
DecorView(Context context, int featureId, PhoneWindow window, WindowManager.LayoutParams params) {
    super(context);
    setWindow(window);
}
void setWindow(PhoneWindow phoneWindow) {
    mWindow = phoneWindow;
}
private PhoneWindow mWindow;

然后切入到generateLayout();方法

protected ViewGroup generateLayout(DecorView decor) {
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    return contentParent;
}

暂时还没发生contentParent的作用, 先记下, 以后遇到大佬赶紧问一波

目前发现好像就只做了几件事:

1、初始化DecorView,将PhoneWindow, Activity, Callback, DecorView产生联系;
2、初始化ViewGroup mContentParent;

然后继续切入到handleLaunchActivity方法:

class ActivityThread->
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
    }
}

4、resume->绘制三部曲:

继续进入到handleResumeActivity()方法发现里面依次调用了measure, layout, draw方法;但是流程感觉很复杂, 估计这次看完, 后面有时间还会回来反复再看几遍.

class ActivityThread->
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    ...
    ActivityClientRecord r = mActivities.get(token);
    r = performResumeActivity(token, clearHide, reason);
    ...
}
class ActivityThread->
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    if (r != null && !r.activity.mFinished) {
        try {
             r.activity.performResume();
        } 
    }
    return r;
}
class Activity->
final void performResume() {
    performRestart();
    mFragments.execPendingActions();
    mInstrumentation.callActivityOnResume(this);
    mFragments.dispatchResume();
    mFragments.execPendingActions();
    onPostResume();
}
class Instrumentation->
public void callActivityOnResume(Activity activity) {
    activity.onResume();
}

然后继续handleResumeActivity方法:

class ActivityThread->
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    r = performResumeActivity(token, clearHide, reason);
    if (r != null) {
        final Activity a = r.activity;
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            ViewManager wm = a.getWindowManager();
            a.mDecor = decor;
            if (a.mVisibleFromClient && !a.mWindowAdded) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            }
        } 
        if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
            if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible();
            }
        }
    } 
}
class Activity->
void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

我们切入到addView里面去看看:

addView最终在WindowManagerImpl中进行的实现;
class WindowManagerImpl->
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
private final Window mParentWindow;
class WindowManagerGlobal->
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    ViewRootImpl root;
    View panelParentView = null;
    synchronized (mLock) {
       int index = findViewLocked(view, false);
       if (index >= 0) {
           root = new ViewRootImpl(view.getContext(), display);
           view.setLayoutParams(wparams);
           mViews.add(view);
           mRoots.add(root);
           mParams.add(wparams);
       }
       try {
           root.setView(view, wparams, panelParentView);
       } 
    }
}
private int findViewLocked(View view, boolean required) {
    final int index = mViews.indexOf(view);
    return index;
}
class ViewRootImpl->
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            requestLayout();
        }
    }
}
View mView;

这部分代码做了一下几件事:

5、绘制三部曲--requestLayout()方法:

先看一看ViewRootImp的结构:

public final class ViewRootImpl implements ViewParent {...}
public interface ViewParent {...}

上面的实现关系可以看出来ViewRootImpl并不是一个View, 他实际上是View的管理工具;

class ViewRootImpl->
@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        mLayoutRequested = true;
        scheduleTraversals();
    }
}
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}
void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        performTraversals();
    }
}

performTraversals()行数太多

class ViewRootImpl->
private void performTraversals() {
    if (mFirst || windowShouldResize || insetsChanged || viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
        if (!mStopped || mReportNextDraw) {
            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        }
        if (didLayout) {
            performLayout(lp, mWidth, mHeight);
        }
        performDraw();
    }
}

1、三部曲->performMeasure:

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 = DecorView;
public class DecorView extends FrameLayout {...}
public class FrameLayout extends ViewGroup {...}
public abstract class ViewGroup extends View implements ViewParent, ViewManager {...}
public class View {...}

上面继承关系, measure方法只有View方法中有:

class View->
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    if (forceLayout || needsLayout) {
        int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
        if (cacheIndex < 0 || sIgnoreMeasureCache) {
            onMeasure(widthMeasureSpec, heightMeasureSpec);
        } 
    }
}
class FrameLayout->
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int count = getChildCount();
    for (int i = 0; i < count; i++) {
         final View child = getChildAt(i);
         if (mMeasureAllChildren || child.getVisibility() != GONE) {
             measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
         }
    }
}
protected void measureChildWithMargins(View child, 
                                       int parentWidthMeasureSpec, int widthUsed,
                                       int parentHeightMeasureSpec, int heightUsed) {
    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

上面代码做了下面几件事:

1、三部曲->performLayout:

class ViewRootImpl-->
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) {
        final View host = mView;
        try {
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
        }
    }
}
mView = DecorView;
class View-->
@SuppressWarnings({"unchecked"})
public void layout(int l, int t, int r, int b) {
    boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
    if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
        onLayout(changed, l, t, r, b);
    }
}
class FrameLayout-->
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    layoutChildren(left, top, right, bottom, false /* no force left gravity */);
}
void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
    final int count = getChildCount();
    for (int i = 0; i < count; i++) {
         final View child = getChildAt(i);
         if (child.getVisibility() != GONE) {
             child.layout(childLeft, childTop, childLeft + width, childTop + height);
         }
    }
}

上面代码做了下面几件事:

到此仅仅是把DecorView, 及其控件的绘制流程搞清楚了, 但是具体的实现细节并没有进行分析, 比如onMeasure和onLayout中大量出现的measureSize, measureMode这种数据的一系列计算全部跳过了, 这个步骤先留着吧, 后边如果有机会去在mac环境下一套源码, 调试着去分析, 不然真没法搞明白里面的道道儿

上一篇下一篇

猜你喜欢

热点阅读