应用程序窗口需要关联一个Window对象来具体描述,Window对象提供一组通用的窗口操作的API。而Window是一个abstact类型,所以实际创建的Window对象是PhoneWindow类型的对象。
PhoneWindow对象的创建是在Activity对象创建之后创建的,而Activity对象的创建在ActivityThread.performLaunchActivity()方法才完成创建的,那么进入该方法看看:
public final class ActivityThread {
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Activity activity = null;
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);//创建Activity对象
......
if (activity != null) {
ContextImpl appContext = new ContextImpl();//创建Context对象
appContext.setOuterContext(activity);//在ContextImpl类中保存当前Activity对象,以便在ContextImpl能操作Activity组件。
......
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
......
return activity;
}
}
在这个函数中,我们只能看到创建了Activity对象,ContextImpl对象。但是在这个函数中调用了 activity.attach函数,进入Activity类中看看attach函数:
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
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) {
attachBaseContext(context);//设置Activity父类中的Context对象的mBase成员变量
mWindow = PolicyManager.makeNewWindow(this);//创建出Window对象
mWindow.setCallback(this);//设置窗口回调接口
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);//设置软键盘输入区域的显示模式
}
......
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());//设置本地窗口管理
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
......
}
从Activity.attach()方法的17行调用了PolicyManager.makeNewWindow(this)创建Window对象并作为返回值保存在Activity类中mWindow的成员变量中,进入该方法看看如何创建的:
public final class PolicyManager {
private static final IPolicy sPolicy;
static {
......
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
......
}
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
}
在第6行,它在第一次被使用的时候,就会创建一个Policy类实例,并且保存在静态成员变量sPolicy中,PolicyManager.makeNewWindow()函数其实就是调用sPolicy.makeNewWindow函数来创建出一个具体的PhoneWindow类,那么就进入Policy类的makeNewWindow去看看:
public class Policy implements IPolicy {
......
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
......
}
从这里,终于知道为什么是创建Window对象其实是创建PhoneWindow对象了,简单粗暴的new出个PhoneWindow对象。
总结一下PhoneWindow对象创建的流程,ActivityThread.performLaunchActivity()—-> activity.attach()—>PolicyManager.makeNewWindow()—>sPolicy.makeNewWindow(context)—>new PhoneWindow(context);
通过这样的流程,PhoneWindow对象就创建出来的,然而在activity.attach()方法中,调用了mWindow =PolicyManager.makeNewWindow();把创建的PhoneWindow对象保存在Activity类中mWindow成员变量中。因此说每一个Activity组件都会关联一个具体的Window对象来描述一个具体的应用程序窗口,而这个对象真正的类型就是PhoneWindow类。
我们继续回到activity.attach()方法中,在创建完PhoneWindow对象后还做几个重要的操作,我们再进入去看看:
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
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) {
attachBaseContext(context);//设置Activity父类中的Context对象的mBase成员变量
mWindow = PolicyManager.makeNewWindow(this);//创建出Window对象
mWindow.setCallback(this);//设置窗口回调接口
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);//设置软键盘输入区域的显示模式
}
......
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());//设置本地窗口管理
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();//保存在Window类的mWindowManager成员变量中
mCurrentConfig = config;
}
......
}
在18行中设置窗口回调接口, 在20行设置软键盘输入区域的显示模式,在24行设置本地窗口管理。在28行中,把WindowManager对象保存在Window类的mWindowManager成员变量中。
我们先去看看设置窗口回调,调用了 mWindow.setCallback(this);mWindow成员变量是Window类 ,实际指向的是PhoneWindow类。
public abstract class Window {
......
private Callback mCallback;
......
public void setCallback(Callback callback) {
mCallback = callback;
}
......
}
从这里可以看出,Activity组件实现了一个Callback接口,然后设置到与它所关联的一个PhoneWindow对象的父类Window的成员变量mCallback中去,这样当这个PhoneWindow对象接收到系统给它分发的IO(触摸,按键)输入事件消息,转发给与它所关联的Activity组件处理。
接下来看看设置窗口的软键盘输入区域的显示模式:
public abstract class Window {
......
private boolean mHasSoftInputMode = false;
......
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;
}
if (mCallback != null) {
mCallback.onWindowAttributesChanged(attrs);
}
}
......
}
设置完软键盘输入区域的显示模式,在14行回调函数onWindowAttributesChanged来通知Window类所关联的Activity组件,窗口布局属性发生了变化。
接下来再看看设置本地窗口管理, mWindow.setWindowManager();,进入Window类的setWindowManger函数:
public abstract class Window {
......
public void setWindowManager(WindowManager wm,
IBinder appToken, String appName) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm);
}
......
}
在第8行调用了 wm = WindowManagerImpl.getDefault();去看看该函数:
public class WindowManagerImpl implements WindowManager {
private static WindowManagerImpl mWindowManager = new WindowManagerImpl()
......
public static WindowManagerImpl getDefault(){
return mWindowManager;
}
......
}
从这里可以看出返回了WindowManagerImpl对象。
然后Window.setWindowManager()函数第10行传入了 WindowManagerImpl对象 new出了LocalWindowManager对象保存在Window类的mWindowManager成员变量中。
总结:Window类 mWindowManager 成员变量—-> 指向的是LocalWindowManager 对象 —->LocalWindowManager 类中成员变量 —–>指向的是 WindowManagerImpl对象 。最终应用程序窗口的管理是的对象是: WindowManagerImpl对象。
那么,我们好像还不知道PhoneWindow类,Window类,Activity类,Window类,WindowManagerImpl类,LocalWindowMangaer类之间的关系?
由继承图可知,它们之间存在着,各种的组合,聚合关系。
聚合:指的是整体与部分的关系。
组合:也表示类之间整体和部分的关系。聚合和组合的区别在于:聚合关系是“has-a”关系,组合关系是“contains-a”关系。
例如:国破家亡”,国灭了,家自然也没有了,“国”和“家”显然也是组合关系。而相反的,计算机和它的外设之间就是聚合关系,因为它们之间的关系相对松散,计算机没了,外设还可以独立存在,还可以接在别的计算机上。
利用聚合,组合主要的作用就是减少耦合。
到这里PhoneWindow对象就是这样创建出来了,再梳理整个流程:
首先在ActivityThread.performLaunchActivity() —>调用了activity.attach()方法。
然后调用PolicyManager.makeNewWindow()—>sPolicy.makeNewWindow(context)—>new PhoneWindow(context);创建出PhoneWindow对象。
创建完PhoneWindow对象还有做了一些操作,函数还会调用它的成员函数setCallback、setSoftInputMode和setWindowManager来设置窗口回调接口、软键盘输入区域的显示模式和本地窗口管理器。
创建WindowManager对象流程:
setWindowManager —>WindowManagerImpl.getDefault()—> new LocalWindowManager(wm);
END