1.Window
Activity中的相關(guān)變量
/** Activity.java */
public class Activity extends ... {
private Instrumentation mInstrumentation;
private IBinder mToken;
...
private Application mApplication;
private Window mWindow;
private WindowManager mWindowManager;
View mDecor = null;
...
}
Activity的啟動(dòng)是由Activity中通過(guò)H這個(gè)handler調(diào)用的芋齿,實(shí)現(xiàn)代碼在ActivityThread中,代碼如下氧急。
/** ActivityThread.java */
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
try {
...
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, r.configCallback);
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
} catch (SuperNotCalledException e) {
...
} catch (Exception e) {
...
}
return activity;
}
剔除大部分代碼我們可以看到斯辰,Activity的實(shí)例化通過(guò)反射的方式實(shí)現(xiàn)的帆焕,Activity在onCreate之前救氯,調(diào)用了attach方法進(jìn)行初始化找田。下面是attach的部分代碼
/**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, ActivityConfigCallback activityConfigCallback) {
...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
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();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
...
}
在attach方法里,會(huì)實(shí)例化一個(gè)PhoneWindow對(duì)象賦值給mWindow變量着憨,并將獲取到的WindowManager傳遞給mWindow墩衙。
2.頁(yè)面布局
我們?cè)贏ctivity的onCreate里,都會(huì)通過(guò)setContentView()設(shè)置界面布局甲抖,我們來(lái)看看setContentView干了啥漆改。
/**Activity.java*/
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);//1
initWindowDecorActionBar();
}
/**PhoneWindow.java*/
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();//2
} 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);//3
}
...
}
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
...
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
1.setContentView在activity類中,會(huì)調(diào)用PhoneWindow的setContentView方法
2.PhoneWindow會(huì)檢查mContentParent准谚,如果沒(méi)有挫剑,會(huì)通過(guò)generateDecor()方法創(chuàng)建出DecorView,進(jìn)而通過(guò)generateLayout方法得到mContentParent氛魁。DecorView是一個(gè)繼承自FrameLayout的子類暮顺,在generateDecor()中,通過(guò)new關(guān)鍵字來(lái)實(shí)例化的秀存。
3.注釋3處的方法我們都不陌生捶码,將mContentParent作為ViewGroup,從xml文件中創(chuàng)建布局或链,mContentParent就是我們布局文件的父布局了惫恼。
繼續(xù)看看generateLayout()方法
//PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
...
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
setCloseOnSwipeEnabled(true);
...
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;//1
// System.out.println("Simple!");
}
mDecor.startChanging();
...
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);//2
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
// Remaining setup -- of background and title -- that only applies
// to top-level windows.
if (getContainer() == null) {//3
final Drawable background;
if (mBackgroundResource != 0) {
background = getContext().getDrawable(mBackgroundResource);
} else {
background = mBackgroundDrawable;
}
mDecor.setWindowBackground(background);
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
}
if (mTitleColor == 0) {
mTitleColor = mTextColor;
}
setTitleColor(mTitleColor);
}
mDecor.finishChanging();
return contentParent;
}
//DecorView.java
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
if (mBackdropFrameRenderer != null) {
loadBackgroundDrawablesIfNeeded();
mBackdropFrameRenderer.onResourcesLoaded(
this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
getCurrentColor(mNavigationColorViewState));
}
mDecorCaptionView = createDecorCaptionView(inflater);
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
// Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mContentRoot = (ViewGroup) root;
initializeElevation();
}
//screen_simple.xml
<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"
android:theme="?attr/actionBarTheme" />
<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>
1.PhoneWindow會(huì)根據(jù)features中的值,假如有設(shè)置澳盐,會(huì)給對(duì)應(yīng)的布局祈纯,實(shí)現(xiàn)相關(guān)的特性,例如第一個(gè)是用來(lái)實(shí)現(xiàn)側(cè)滑關(guān)閉當(dāng)前Activity的功能叼耙。如果都沒(méi)設(shè)置的話腕窥,會(huì)給screen_simple.xml,布局代碼在下方筛婉。
2.DecorView通過(guò)onResourcesLoaded方法簇爆,將給定的布局添加到DecorView中。其中id為content就是contentParent爽撒。我們寫(xiě)的頁(yè)面布局都將加入到這個(gè)contentParent中入蛆。
3.window可以有container,這個(gè)container也是個(gè)window硕勿。只有最頂層的window才會(huì)設(shè)置背景和標(biāo)題哨毁。
小結(jié):
每一個(gè)Activity都有個(gè)PhoneWindow對(duì)象,并且這個(gè)PhoneWindow對(duì)象有個(gè)DecorView視圖對(duì)象源武,Activity的視圖都掛在DecorView的mContentParent節(jié)點(diǎn)下扼褪。那么視圖是如何更新的呢,我們繼續(xù)看粱栖。
3.頁(yè)面更新流程
在ActivityThread內(nèi)部類H的handleMessage方法中迎捺,在EXECUTE_TRANSACTION這個(gè)分支中,對(duì)應(yīng)的Activity的生命周期查排,在處理ResumeActivityItem的execute方法時(shí)凳枝,會(huì)調(diào)用ActivityThread的handleResumeActivity方法。我們看看該方法的實(shí)現(xiàn)
//ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
final Activity a = r.activity;
...
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManager.getService().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
if (r.window == null && !a.mFinished && willBeVisible) {//1
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);//2
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
...
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
performConfigurationChangedForActivity(r, r.newConfig);
if (DEBUG_CONFIGURATION) {
Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig "
+ r.activity.mCurrentConfig);
}
r.newConfig = null;
}
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);//3
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
...
}
1.ActivityClientRecord r跋核,這是個(gè)記錄Activity相關(guān)信息的對(duì)象岖瑰,該對(duì)象在Activity對(duì)象實(shí)例化之前被創(chuàng)建出來(lái),并且該類的參數(shù)用來(lái)實(shí)例化Activity砂代√6可以說(shuō)先有的r,然后activity被創(chuàng)建出來(lái)刻伊,然后activity在attach的時(shí)候擁有了window露戒。然后這時(shí)候在這里椒功,r還有沒(méi)window,所以會(huì)從注釋1進(jìn)去智什,賦值window成員變量动漾。因?yàn)槭堑谝淮危栽谧⑨?處荠锭,調(diào)用wm.addView(decor,l)旱眯。隨后會(huì)調(diào)用注釋3處的wm.updateViewLayout(decor, l)
2.wm是一個(gè)WindowManagerImpl實(shí)例(在Window類里面賦值),addView和updateViewLayout兩個(gè)方法在WindowManagerImpl中是交給WindowManagerGlobal這個(gè)單例處理证九。在WindowManagerGlobal中删豺,addView時(shí),創(chuàng)建一個(gè)與根view相對(duì)應(yīng)的ViewRootImpl愧怜。
3.在updateViewLayout時(shí)呀页,ViewRootImpl會(huì)調(diào)用setLayoutParams,調(diào)用scheduleTraversals拥坛,借助于mChoreographer去執(zhí)行doTraversal()方法赔桌,該方法會(huì)執(zhí)行view的measure,layout渴逻,draw方法疾党。使用mThreadedRenderer渲染,使用mWindowSession與WindowManagerService通信惨奕。
參考
Android源碼分析-Activity的啟動(dòng)過(guò)程
Android視圖框架Activity,Window,View,ViewRootImpl理解