1录择、Activity,Window碗降,View是什么隘竭?
在開始之前,我們先來回憶一下我們對(duì)Activity
讼渊,Window
动看,View
的印象;
Activity:Android
四大組件之一精偿,也是我們最常見的頁(yè)面的宿主弧圆,通過setContentView
將xml布局赋兵,解析并展示到頁(yè)面上笔咽;
Window:窗口,這是一個(gè)抽象類霹期,真正的實(shí)現(xiàn)類在PhoneWindow
里叶组,用來管理View
的展示以及事件的分發(fā);
View:Android
的視圖历造,是各種炫酷控件的最終父類甩十,維護(hù)了繪制流程以及事件的分發(fā)和處理船庇;
下面通過一張圖來了解它們的對(duì)應(yīng)關(guān)系:
紙上得來終覺淺,絕知此事要躬行侣监!接下來讓我們通過源碼深入看看底層實(shí)現(xiàn)吧鸭轮;
2、Activity和Window橄霉,View的關(guān)系窃爷;
(1)從上面的一張關(guān)系圖了解到Activity
和Window
是包含的關(guān)系,而Window
的實(shí)現(xiàn)是在PhoneWindow
里面姓蜂,那么Activity
和Window
的關(guān)系可以理解為Activity
和PhoneWindow
的關(guān)系按厘;到這里就有一個(gè)疑問了,為什么Activity
和PhoneWindow
是包含的關(guān)系钱慢?而不是平等的逮京,或者對(duì)稱的關(guān)系呢?
(2)要想理清它們的關(guān)系束莫,目前并沒有什么好的頭緒懒棉,但是我們可以先從Activity
的來源來進(jìn)行分析,試著從Activity
的來源中能否找到它們的對(duì)應(yīng)關(guān)系览绿;說到Activity
的來源漓藕,我們就不得不來分析一下Activity
的啟動(dòng)流程,看看Activity
究竟是何方神圣挟裂!
(3)Activity
的啟動(dòng)流程涉及到很多系統(tǒng)服務(wù)享钞,要完整的分析,會(huì)花上很大的篇章诀蓉,等看完Activity
的啟動(dòng)流程之后栗竖,估計(jì)我們都忘了看這篇博客的目的的;為了簡(jiǎn)化流程渠啤,這里會(huì)從Activity
的創(chuàng)建的方法開始講起狐肢;
Activity的創(chuàng)建是在ActivityThread
的handleLaunchActivity()
方法里面,我們就從這個(gè)方法進(jìn)行分析沥曹;
在開始之前份名,我們先來看幾個(gè)問題:
- 1、在哪里創(chuàng)建Window妓美,創(chuàng)建的Window用來干嘛的僵腺;
- 2、Activity和Window的關(guān)系壶栋;
- 3辰如、Activity和View的關(guān)系;
源碼分析:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
// Initialize before creating the activity
// 初始化WindowManagerService
WindowManagerGlobal.initialize();
//step1:
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
...
// step2:
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
...
} else {
...
}
}
這里面主要分為兩步操作贵试,第一步是調(diào)用performLaunchActivity
方法琉兜,第二步是調(diào)用handleResumeActivity
方法凯正,先來看一下performLaunchActivity
方法;
2.1. performLaunchActivity
方法解析:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
...
// Step1:
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
// Step2:
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
try {
// Step3:
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
...
// Step4:
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);
...
activity.mCalled = false;
// Step5:
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
return activity;
}
Step1:
通過調(diào)用createBaseContextForActivity
創(chuàng)建Activity
的上下文Context
豌蟋,而Context
是一個(gè)抽象類廊散,具體的實(shí)現(xiàn)是在ContextImpl
里面;
Step2:
通過調(diào)用mInstrumentation
的newActivity
來創(chuàng)建Activity
的實(shí)例梧疲,里面是通過反射的方式進(jìn)行創(chuàng)建的奸汇;Instrumentation
這個(gè)類底層實(shí)現(xiàn)是代理模式,用戶代理Activity
的各種生命周期的操作往声;
而
newActivity
方法里通過工廠模式來創(chuàng)建Activity
的實(shí)例擂找;
最終通過
ClassLoader
來創(chuàng)建Activity
的實(shí)例;
Step3:
通過調(diào)用LoadedApk
的makeApplication
方法來創(chuàng)建全局的上下文Application
Step4:
調(diào)用Activity
的attach
來進(jìn)行初始化浩销,將之前創(chuàng)建的上下文傳進(jìn)去贯涎;
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) {
// 將Context賦值給Activity
attachBaseContext(context);
// 將fragment添加到host
mFragments.attachHost(null /*parent*/);
// 創(chuàng)建PhoneWindo的實(shí)例
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);
}
...
// 給Window設(shè)置管理器,通過系統(tǒng)服務(wù)獲取的管理器
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
}
這里面做的主要操作就是創(chuàng)建了Window
和WindowManager
的實(shí)例慢洋,Window
的實(shí)現(xiàn)是在PhoneWindow
里面塘雳,而WindowManager
的實(shí)現(xiàn)是在WindowManagerImpl
里面;
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
Step5:
當(dāng)Window
創(chuàng)建完了之后普筹,就會(huì)觸發(fā)Activity
的onCreate
方法败明,通過代理類mInstrumentation
的callActivityOnCreate
方法,最終調(diào)用到Activity
的onCreate
方法太防;
看一下總結(jié)流程圖:
2.2. Activity
中的onCreate
方法的調(diào)用:
Step1:
Activity
的onCreate
方法調(diào)用了setContentView
來進(jìn)行布局的加載妻顶;
Step2:
走了父類AppCompatActivity
的setContentView
方法,這里調(diào)用了getDelegate
獲取實(shí)例AppCompatDelegate
蜒车,AppCompatDelegate
是一個(gè)抽象類讳嘱,具體實(shí)現(xiàn)是在AppCompatDelegateImpl
里面;
Step3:
AppCompatDelegateImpl
里的setContentView
方法酿愧,調(diào)用了ensureSubDecor
方法來創(chuàng)建DecorView
沥潭,繼續(xù)跟蹤源碼往下看;
Step4:
這里調(diào)用了createSubDecor
方法嬉挡,而這里會(huì)走到Window
的setContentView
方法钝鸽;
到這里似乎有一些眉目了,Activity的setContentView
會(huì)通過Window
的setContentView
來設(shè)置布局庞钢,那么可以理解為Window
管理著Activity
對(duì)于View
的一些相關(guān)操作拔恰;那到底是不是這樣呢,繼續(xù)跟蹤分析焊夸;
Step5:
Window
的實(shí)現(xiàn)是在PhoneWindow
里面仁连,來看一下PhoneWindow
里的setContentView
的邏輯;
這里調(diào)用了installDecor
方法阱穗;
最終調(diào)用了generateDecor
來創(chuàng)建DecorView
饭冬;
看一下流程圖:
小結(jié):到這里,
performLaunchActivity
的方法就分析完了揪阶,這里的源碼看到創(chuàng)建了Window
昌抠,并且通過PhoneWindow
的setContentView
來創(chuàng)建DecorView
的操作;這里可以理解為Window
管理著Activity
關(guān)于View
的一些操作鲁僚;
這里并沒有發(fā)現(xiàn)Activity
和DecorView
的關(guān)聯(lián)炊苫,接下來看一下handleResumeActivity
方法,進(jìn)一步跟蹤看看是否有關(guān)聯(lián)冰沙;
2.3. handleResumeActivity
方法解析:
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
// 通過token獲取記錄當(dāng)前Activity的信息類
ActivityClientRecord r = mActivities.get(token);
// TODO Push resumeArgs into the activity for consideration
// Stpe1:
r = performResumeActivity(token, clearHide, reason);
if (r != null) {
...
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
// 判斷是否要添加window
// Stpe2:
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) {
// 將創(chuàng)建Window和decorView賦值給信息記錄類
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;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 通過manager將decorView添加到頁(yè)面去侨艾;
// 具體實(shí)現(xiàn)是在
// Stpe3:
wm.addView(decor, l);
} else {
...
}
}
// 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) {
// 判斷window已經(jīng)被添加了,就不展示這個(gè)Window了拓挥;
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
...
}
Step1:
調(diào)用了performResumeActivity
方法來觸發(fā)Activity
的onResume
方法唠梨;
主要是調(diào)用了Activity
的performResume
方法;
@VisibleForTesting
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
String reason) {
final ActivityClientRecord r = mActivities.get(token);
...
try {
...
r.activity.performResume(r.startsNotResumed, reason);
} catch (Exception e) {
...
}
return r;
}
來看一下performResume
方法侥啤,
final void performResume(boolean followedByPause, String reason) {
// 觸發(fā)Activity的onStart方法当叭;
performRestart(true /* start */, reason);
mFragments.execPendingActions();
mLastNonConfigurationInstances = null;
mCalled = false;
// mResumed is set by the instrumentation
// 通過代理類Instrumentation來回調(diào)Activity的onReusme方法;
mInstrumentation.callActivityOnResume(this);
// 回調(diào)fragment的onResume方法盖灸;
mFragments.dispatchResume();
mFragments.execPendingActions();
onPostResume();
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPostResume()");
}
}
這里面主要分為三步:
第一步:通過performRestart
回調(diào)Activity
的onStart
方法蚁鳖;
第二步:通過代理類
Instrumentation
來回調(diào)Activity
的onReusme
方法;
第三步:回調(diào)
fragment
的onResume
方法赁炎;
Step2:
通過系統(tǒng)服務(wù)來判斷當(dāng)前窗口如果還沒有被添加到窗口管理器中醉箕,就添加該窗口,將頁(yè)面設(shè)置為可見狀態(tài)徙垫;
Step3:
將DecorView
添加到WindowManager
里去琅攘,ViewManager
是一個(gè)抽象類,由前面的分析得知松邪,WindowManager
的實(shí)現(xiàn)是在WindowManagerImpl
里面坞琴,來看一下WindowManagerImpl
的addView
方法;
最終走的是WindowManagerGlobal
的addView
方法逗抑;
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
// 創(chuàng)建頂層的View視圖管理類
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
將當(dāng)前的DecorView設(shè)置給ViewRootImpl
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
在這里創(chuàng)建了頂層的View
視圖管理類ViewRootImpl
剧辐,并將DecorView
設(shè)置給ViewRootImpl
;
來看看ViewRootImpl
的setView
方法做了啥邮府?
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
// 觸發(fā)View樹的布局與繪制
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
}
}
}
這里最終會(huì)調(diào)用requestLayout
方法觸發(fā)View
樹的繪制荧关;
第一步:調(diào)用了scheduleTraversals
方法;
第二步:調(diào)用了doTraversal
方法褂傀;
第三步:調(diào)用了performTraversals
方法忍啤;
而performTraversals
最終調(diào)用了performMeasure
,performLayout
,performDraw
三個(gè)大步驟完成對(duì)View
樹的繪制同波;
這個(gè)流程在之前的一篇博客里面已經(jīng)分析過了鳄梅,感興趣的可以去看看;
到這里handleResumeActivity
方法差不多就分析完了未檩,在這里我們理清了Activity
和View
之間的關(guān)系戴尸,是通過Window
的管理器WindowManger
來觸發(fā)View
的繪制的,也就是說Activity
的View
的繪制流程都是交由Window
的WindowManger
來管理的冤狡;
看一下流程圖:
讓我們來回憶一下開頭提到的幾個(gè)問題孙蒙;
- 1、在哪里創(chuàng)建
Window
悲雳,創(chuàng)建的Window
用來干嘛的挎峦?
在Activity
的attach
方法里面創(chuàng)建了Window
的實(shí)現(xiàn)類PhoneWindow
,用于管理View
的創(chuàng)建以及和ViewRootIml
進(jìn)行一些操作合瓢; - 2坦胶、
Activity
和Window
的關(guān)系?
Window
相當(dāng)于Activity
的代理類,用于管理View
的創(chuàng)建歪玲,以及后續(xù)View樹繪制的一些操作迁央; - 3、
Activity
和View
的關(guān)系?
Activity
不直接操作View
滥崩,通過代理類Window
來管理View
的創(chuàng)建以及繪制流程岖圈;
關(guān)于我
兄dei,如果我的文章對(duì)你有幫助的話钙皮,請(qǐng)幫我點(diǎn)個(gè)贊吧?蜂科,也可以關(guān)注一下我的Github和博客;