Android_窗口绘制相关流程

看到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();
    }
  • 调用setCallback将window与activity产生关联, 而window实际上是PhoneWindow; 切入到Window中去观察setCallback();
public void setCallback(Callback callback) {
    mCallback = callback;
}
public interface Callback {
    ...
    public boolean dispatchTouchEvent(MotionEvent event);
    public void onWindowFocusChanged(boolean hasFocus);
    ...
}
  • Callback是一系列的回调函数的集合, 先记下来以后再看看是如何实现回调的

从上面代码可以试着分析一波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实际上指向子类PhoneWindow;
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;
  • 1、WindowManagerImpl中的mParent实际上指向的是PhoneWindow;
  • 2、mWindowManager实际上指向的WindowManagerImpl;
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    ...
}
  • 1、isPersistable关于持久化存储的一个玩意儿, 先记下来, 留待以后分析
  • 2、目前先重点分析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();
}
  • 1、onCreate()方法由performLaunchActivity调用
  • 2、注意到mFragments与attach方法中都有mFragments出现, 先记下来, 以后分析.

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

3、setContentView:

class Activity->
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}
public Window getWindow() {
    return mWindow;
}
  • 前面在attach()方法时已经将PhoneWindow赋值给了Window. 所以切入到PhoneWindow
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;
  • 1、创建DecorView对象, 并对DecorView中的PhoneWindow进行赋值.
  • 2、前文中的attach种进行了mWindow.setCallback(this)将PhoneWindow, Activity, Callback三者绑定了关系, 这里又将PhoneWindow赋值给DecorView中的PhoneWindow, 也就是将PhoneWindow, Activity, Callback, DecorView四者产生了关联;

然后切入到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();
}
  • 貌似performResumeActivity()就做了一件事, 调用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);
}
  • 1、r.window = activity.getWindow()将PhoneWindow赋值给ActivityClientRecord中的Window;
  • 2、a.getWindowManager()将WindowManagerImpl赋值给ViewManager;
  • 3、wm.addView(decor, l);接下来重点分析一波
  • 4、然后调用mDecor.setVisibility(View.VISIBLE); 进行UI显示;

我们切入到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;

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

  • 1、创建ViewRootImpl对象
  • 2、root.setView(view)将DecorView赋值给View;
  • 3、调用requestLayout()方法;

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;
  • 1、由前面代码知道mView其实是decorView;
  • 2、接下来是对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、调用DecorView中的measure方法, 该方法只在父类View中有
  • 2、所以调用View中的measure方法, 然后调用到里面的onMeasure()方法;
  • 3、而onMeasure()方法又只有父类FrameLayout中有, 所以执行FrameLayout方法中的onMeasure方法. 该方法会遍历子类, 然后依次调用子类的measure方法.

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

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

  • 1、调用DecorView的layout方法, 实际上调用View的layout方法
  • 2、layout调用onLayout方法, onLayout方法被DecorView的父类FrameLayout方法重写, 实际调用FrameLayout的onLayout方法
  • 3、然后遍历DecorView里面的控件, 并对遍历的控件调用其layout方法;

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容