每一個(gè)Activity組件都有一個(gè)關(guān)聯(lián)的ContextImpl對(duì)象,同時(shí)秫舌,它還關(guān)聯(lián)有一個(gè)Window對(duì)象梦重,用來(lái)描述一個(gè)具體的應(yīng)用程序窗口赏壹。與Activity組件所關(guān)聯(lián)的窗口對(duì)象的實(shí)際類型為PhoneWindow炊甲。
那么創(chuàng)建這個(gè)window的過程就如圖所示:
上面的圖可以分為9個(gè)步驟,接下來(lái)我們開始分析每一個(gè)步驟
如果想研究Activity中的Window創(chuàng)建過程就必須知道Activity的啟動(dòng)過程欲芹,這里不做具體講解卿啡,我們只要知道最終會(huì)由ActivityThread中的performLaunchActivity()來(lái)完成整個(gè)啟動(dòng)過程的,這個(gè)過程中會(huì)調(diào)用Activity的attach方法為activity關(guān)聯(lián)運(yùn)行過程中所依賴的一系列上下文環(huán)境變量菱父。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......省略部分
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(activity);
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);
......省略部分
return activity;
}
步驟一:Activity.attach
在Activity的attach方法里颈娜,系統(tǒng)會(huì)創(chuàng)建Activity所屬的Window對(duì)象并為它設(shè)置回調(diào)接口,首先是調(diào)用PolicyManager的makeNewWindow來(lái)創(chuàng)建一個(gè)類型為PhoneWindow的應(yīng)用程序窗口浙宜,并且保存在Activity類的成員變量mWindow中官辽,因?yàn)樵O(shè)置了Callback接口,所以當(dāng)外界的狀態(tài)改變的時(shí)候Activity就能感知到并做出回應(yīng)處理粟瞬。
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
private Window mWindow;
......
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,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
......
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
......
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
......
}
......
}
步驟二:PolicyManager.makeNewWindow
Activity的Window是通過PolicyManager的一個(gè)方法創(chuàng)建的同仆, PolicyManager是一個(gè)窗口管理策略類,它在第一次被使用的時(shí)候裙品,就會(huì)創(chuàng)建一個(gè)Policy類實(shí)例俗批,并且保存在靜態(tài)成員變量sPolicy中,而PolicyManager的makeNewWindow方法其實(shí)就是調(diào)用的sPolicy.makeNewWindow(context);來(lái)實(shí)現(xiàn)的。
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static {
// Pull in the actual implementation of the policy at run-time
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
} catch (InstantiationException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
}
}
......
// The static methods to spawn new policy-specific objects
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
......
}
步驟三:Policy.makeNewWindow
這個(gè)方法就跟簡(jiǎn)單了就是創(chuàng)建了一個(gè)PhoneWindow對(duì)象市怎,然后返回給了調(diào)用者了.
public class Policy implements IPolicy {
......
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
......
}
步驟四:new PhoneWindow
下面代碼可以發(fā)現(xiàn)岁忘,使用LayoutInflater.from創(chuàng)建了一個(gè)LayoutInflater,PhoneWindow使用它來(lái)創(chuàng)建窗口的視圖区匠,并放在類型為ViewGroup的成員變量mContentParent中干像,這個(gè)稍后會(huì)講。
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
這個(gè)Context通過一層層的調(diào)用我們知道正是當(dāng)前啟動(dòng)的這個(gè)Activity,這樣一來(lái)那麻汰,PhoneWindow就可以訪問與Activity組件相關(guān)的資源了速客。接下來(lái)我們接著回到第一個(gè)步驟,在Activity的attach中創(chuàng)建了Window什乙,來(lái)給當(dāng)前的Activity通過setCallback來(lái)設(shè)置窗口回調(diào)接口挽封。接下來(lái)就分析一下這個(gè)方法
步驟五:Window.setCallback
當(dāng)我們給Activity設(shè)置上回調(diào)的時(shí)候Callback接口中的方法很多,這樣當(dāng)這個(gè)PhoneWindow對(duì)象接收到系統(tǒng)給它分發(fā)的IO輸入事件臣镣,例如辅愿,鍵盤和觸摸屏事件,轉(zhuǎn)發(fā)給與它所關(guān)聯(lián)的Activity組件處理忆某,点待,我們比較熟悉的方法有:dispatchTouchEvent,onAttachedToWindow弃舒,等等吧癞埠。
public abstract class Window {
......
private Callback mCallback;
......
/**
* Set the Callback interface for this window, used to intercept key
* events and other dynamic operations in the window.
*
* @param callback The desired Callback interface.
*/
public void setCallback(Callback callback) {
mCallback = callback;
}
......
}
步驟六:Window.setSoftInputMode
接著第一步驟繼續(xù)往下走,設(shè)置應(yīng)用程序窗口的軟鍵盤輸入?yún)^(qū)域的顯示模式,此方法中首先判斷當(dāng)參數(shù)mode的值是否等于SOFT_INPUT_STATE_UNSPECIFIED聋呢,如果不等于苗踪,就表示當(dāng)前窗口被指定軟鍵盤輸入?yún)^(qū)域的顯示模式,然后調(diào)用函數(shù)onWindowAttributesChanged來(lái)通知與窗口所關(guān)聯(lián)的Activity組件削锰,它的窗口布局屬性發(fā)生了變化通铲。
public void setSoftInputMode(int mode) {
final WindowManager.LayoutParams attrs = getAttributes();
if (mode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
attrs.softInputMode = mode;
mHasSoftInputMode = true;
} else {
mHasSoftInputMode = false;
}
dispatchWindowAttributesChanged(attrs);
}
步驟七:Window.setWindowManager
我們繼續(xù)來(lái)看Activity的attach方法,接下來(lái)就到了調(diào)用Window的setWindowManager來(lái)實(shí)現(xiàn)窗口管理器贩。
appToken保存了當(dāng)前處理的窗口是與哪一個(gè)Activity組件關(guān)聯(lián)的颅夺。
appName用來(lái)描述當(dāng)前正在處理的窗口所關(guān)聯(lián)的Activity組件的名稱。
wm是用來(lái)描述一個(gè)窗口管理者蛹稍,一開始傳進(jìn)來(lái)的就是一個(gè)null所以會(huì)創(chuàng)建一個(gè)窗口管理器吧黄,然后再使用它創(chuàng)建一個(gè)本地窗口管理器即可用來(lái)維護(hù)當(dāng)前正在處理的應(yīng)用程序窗口。
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
步驟八:mContext.getSystemService(Context.WINDOW_SERVICE);
因?yàn)楫?dāng)前的mContext是傳入的Activity唆姐,所以調(diào)用的是Activity的getSystemService拗慨,判斷傳入的name等于WINDOW_SERVICE,返回了一個(gè)WindowManager奉芦。
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
步驟九: ((WindowManagerImpl)wm).createLocalWindowManager(this);
創(chuàng)建一個(gè)WindowManagerImpl胆描,類繼承WindowManager,所以就是創(chuàng)建了一個(gè)窗口管理仗阅。這樣就可以使用窗口管理器來(lái)管理應(yīng)用程序窗口了
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
至此昌讲,我們就分析完成一個(gè)Activity組件所關(guān)聯(lián)的應(yīng)用程序窗口對(duì)象的創(chuàng)建過程了。如果有錯(cuò)誤的地方希望大家多多指出來(lái)减噪,此時(shí)視圖還沒有添加上來(lái)短绸,接下來(lái)的一篇我們將分析應(yīng)用窗口視圖對(duì)象的添加過程车吹!