看到setContentView時(shí), 感覺又要把Activity的啟動(dòng)流程看一遍, 然后又要繼續(xù)往上看, 不知道何時(shí)才能正式進(jìn)入窗口繪制流程, 下面先把需要做的準(zhǔn)備工作記錄下來:
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加載對應(yīng)的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();
}
- 調(diào)用setCallback將window與activity產(chǎn)生關(guān)聯(lián), 而window實(shí)際上是PhoneWindow; 切入到Window中去觀察setCallback();
public void setCallback(Callback callback) {
mCallback = callback;
}
public interface Callback {
...
public boolean dispatchTouchEvent(MotionEvent event);
public void onWindowFocusChanged(boolean hasFocus);
...
}
- Callback是一系列的回調(diào)函數(shù)的集合, 先記下來以后再看看是如何實(shí)現(xiàn)回調(diào)的
從上面代碼可以試著分析一波WindowManager, ViewManager, WindowManagerImpl, PhoneWindow, Window的關(guān)系
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實(shí)際上指向子類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實(shí)際上指向的是PhoneWindow;
- 2吴攒、mWindowManager實(shí)際上指向的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關(guān)于持久化存儲(chǔ)的一個(gè)玩意兒, 先記下來, 留待以后分析
- 2男旗、目前先重點(diǎn)分析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調(diào)用
- 2、注意到mFragments與attach方法中都有mFragments出現(xiàn), 先記下來, 以后分析.
**onCreate()方法被調(diào)用了, 我們通常在onCreate()里面調(diào)用setContentView()方法對窗口進(jìn)行繪制;
3察皇、setContentView:
class Activity->
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
- 前面在attach()方法時(shí)已經(jīng)將PhoneWindow賦值給了Window. 所以切入到PhoneWindow
class PhoneWindow->
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
}
}
第一次進(jìn)入onCreate方法調(diào)用setContentView方法時(shí), mContentParent=null; 切入到installDecor方法中
class PhoneWindow->
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor(-1);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
}
此時(shí)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茴厉、創(chuàng)建DecorView對象, 并對DecorView中的PhoneWindow進(jìn)行賦值.
- 2泽台、前文中的attach種進(jìn)行了mWindow.setCallback(this)將PhoneWindow, Activity, Callback三者綁定了關(guān)系, 這里又將PhoneWindow賦值給DecorView中的PhoneWindow, 也就是將PhoneWindow, Activity, Callback, DecorView四者產(chǎn)生了關(guān)聯(lián);
然后切入到generateLayout();方法
protected ViewGroup generateLayout(DecorView decor) {
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
return contentParent;
}
暫時(shí)還沒發(fā)生contentParent的作用, 先記下, 以后遇到大佬趕緊問一波
目前發(fā)現(xiàn)好像就只做了幾件事:
1、初始化DecorView,將PhoneWindow, Activity, Callback, DecorView產(chǎn)生聯(lián)系;
2矾缓、初始化ViewGroup mContentParent;
然后繼續(xù)切入到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->繪制三部曲:
繼續(xù)進(jìn)入到handleResumeActivity()方法發(fā)現(xiàn)里面依次調(diào)用了measure, layout, draw方法;但是流程感覺很復(fù)雜, 估計(jì)這次看完, 后面有時(shí)間還會(huì)回來反復(fù)再看幾遍.
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()就做了一件事, 調(diào)用activity的onResume()方法;
然后繼續(xù)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);接下來重點(diǎn)分析一波
- 4、然后調(diào)用mDecor.setVisibility(View.VISIBLE); 進(jìn)行UI顯示;
我們切入到addView里面去看看:
addView最終在WindowManagerImpl中進(jìn)行的實(shí)現(xiàn);
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琉雳、創(chuàng)建ViewRootImpl對象
- 2样眠、root.setView(view)將DecorView賦值給View;
- 3、調(diào)用requestLayout()方法;
5翠肘、繪制三部曲--requestLayout()方法:
先看一看ViewRootImp的結(jié)構(gòu):
public final class ViewRootImpl implements ViewParent {...}
public interface ViewParent {...}
上面的實(shí)現(xiàn)關(guān)系可以看出來ViewRootImpl并不是一個(gè)View, 他實(shí)際上是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()行數(shù)太多
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、由前面代碼知道m(xù)View其實(shí)是decorView;
- 2束倍、接下來是對decorView進(jìn)行測量;
public class DecorView extends FrameLayout {...}
public class FrameLayout extends ViewGroup {...}
public abstract class ViewGroup extends View implements ViewParent, ViewManager {...}
public class View {...}
上面繼承關(guān)系, 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被丧、調(diào)用DecorView中的measure方法, 該方法只在父類View中有
- 2、所以調(diào)用View中的measure方法, 然后調(diào)用到里面的onMeasure()方法;
- 3绪妹、而onMeasure()方法又只有父類FrameLayout中有, 所以執(zhí)行FrameLayout方法中的onMeasure方法. 該方法會(huì)遍歷子類, 然后依次調(diào)用子類的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、調(diào)用DecorView的layout方法, 實(shí)際上調(diào)用View的layout方法
- 2邮旷、layout調(diào)用onLayout方法, onLayout方法被DecorView的父類FrameLayout方法重寫, 實(shí)際調(diào)用FrameLayout的onLayout方法
- 3黄选、然后遍歷DecorView里面的控件, 并對遍歷的控件調(diào)用其layout方法;
到此僅僅是把DecorView, 及其控件的繪制流程搞清楚了, 但是具體的實(shí)現(xiàn)細(xì)節(jié)并沒有進(jìn)行分析, 比如onMeasure和onLayout中大量出現(xiàn)的measureSize, measureMode這種數(shù)據(jù)的一系列計(jì)算全部跳過了, 這個(gè)步驟先留著吧, 后邊如果有機(jī)會(huì)去在mac環(huán)境下一套源碼, 調(diào)試著去分析, 不然真沒法搞明白里面的道道兒