frameworks
/
base
/
core
/
java
/
android
/
app
/
ActivityThread.java
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);
能看到在这个步骤中,对着实例化的Activity做了一次绑定操作。具体做什么呢?
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) {
attachBaseContext(context);
mFragments.attachHost(null );
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);
...
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
....
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中实际上最为重要的工作就是实例化一个PhoneWindow对象,并且把当前Phone相关的监听,如点击事件的回调,窗体消失的回调等等。
并且把ActivityThread,ActivityInfo,Application等重要的信息绑定到当前的Activity。
从上一个专栏WMS,就能知道,实际上承载视图真正的对象实际上是Window窗口。那么这个Window对象又是什么做第一次的视图加载呢?
其实是调用了我们及其熟悉的api:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
在这个api中设置了PhoneWindow的内容视图区域。这也是每一个Android开发的接触到的第一个api。因为其至关重要承载了Android接下来要显示什么内容。
接下来我们很容易想到setContentView究竟做了什么事情,来初始化所有的View对象。
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
....
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
mContentParentExplicitlySet = true;
我们这里只关注核心逻辑。能看到当mContentParent为空的时候,会调用installDecor生成一个父容器,最终会通过我们另一个熟悉的函数LayoutInflater.inflate把所有的View都实例化出来。
那么同理,我们把整个步骤分为2部分:
1.installDecor生成DecorView安装在FrameLayout作为所有View的顶层View
2.LayoutInflater.inflate 实例化传进来的内容。
frameworks/base/core/java/android/app/SystemServiceRegistry.java
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
能看到系统初期实例化的是一个PhoneLayoutInflater,并非是一个普通的LayoutInflater,而这个类重载了一个很重要的方法:
文件:http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/com/android/internal/policy/PhoneLayoutInflater.java
private static final String[] sClassPrefixList = {
"android.widget.",
"android.webkit.",
"android.app."
@Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
for (String prefix : sClassPrefixList) {
try {
View view = createView(name, prefix, attrs);
if (view != null) {
return view;
} catch (ClassNotFoundException e) {
return super.onCreateView(name, attrs)
;
能看到这样就手动为View添加了前缀,还是调用了createView创建View。举个例子,如果是一个Linearlayout,就会为这个标签添加android.widget.前缀,称为android.widget.Linearlayout。这样就能找到相对完整的类名。