参考书籍: <Android 内核剖析>
- 每个应用窗口都对应一个
Activity
对象,创建应用类窗口首先需要创建一个Activity
对象.
// ActivityThread.java
public final class ActivityThread {
//创建Activity对象
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
//获取类加载器
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
// TODO 第一
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
...
try {
if (activity != null) {
//TODO 第三 去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);
}
}
//TODO 第五 callActivityOnCreate()方法最终会调用Activity.onCreate()
mInstrumentation.callActivityOnCreate(activity, r.state);
...
return activity;
}
// TODO 第十三, 当执行完第十二步之后,也就是Activity已经准备好了,最后会通知AMS,然后AMS经过调用,最终会执行到ActivityThread中的handleResumeActivity()
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
// ActivityClientRecord对象的来历这里简单的说一下, 是在ApplicationThread中的scheduleLaunchActivity()被调用时候创建的.
// 之后ActivityThread.performLaunchActivity()被调用存入变量mActivities集合中.
// performLaunchActivity()被调用时会创建一个Activity,这个Activity对象也会被保存在ActivityClientRecord对象的activity变量中.
ActivityClientRecord r = performResumeActivity(token, clearHide);
//ActivityClientRecord 中的变量activity对应的是将要在手机中展示的Activity.
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
// 创建该activity时候的PhoneWindow.
r.window = r.activity.getWindow();
// 通过PhoneWindow获取decor
View decor = r.window.getDecorView();
...
// 将PhoneWinodw的decor赋值给Activity的mDecor变量,这个地方很容易忽略.当Activity要显示内容的时候,
a.mDecor = decor;
...
}
if (r.activity.mVisibleFromClient) {
// TODO 第十四 这里将要开始将Activity中的内容展示出来了.
r.activity.makeVisible();
}
}
}
// Activity.java
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks {
// TODO 第三
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);
// TODO 第四 创建PhoneWindow
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
...
// 创建 为PhoneWindow对象创建WindowManagerImpl对象变量和 Window.LocalWindowManager对象变量
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
...
mWindowManager = mWindow.getWindowManager();
}
// TODO 第六
// 这个方法再熟悉不过了 经常用到得onCreate方法
protected void onCreate(Bundle savedInstanceState) {
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mCalled = true;
//在Activity的子类中会重载onCreate方法,里面模板代码setContentView(R.layout.XXXX),我们现在来看看setContentView()方法
}
//TODO 第七
public void setContentView(int layoutResID){
// TODO 第八 看看PhoneWindow中的setContentView()方法
getWindow().setContentView(layoutResID);
}
// TODO 第十四 再往下就是WMS那块的知识了,另外起一片笔记再来记录.
void makeVisible() {
if (!mWindowAdded) {
// 获取Window.LocalWindowManager对象
ViewManager wm = getWindowManager();
// 最终会调到WindowManagerImpl.addView()
// 接着会调到ViewRoot.setView()
// 最后得跨进程了 sWindowSession.add(mWindow, mWindowAttributes,getHostVisibility(), mAttachInfo.mContentInsets,mInputChannel);
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
}
// PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
// TODO 第八
@Override
public void setContentView(int layoutResID) {
//这是创建Activity 所以mContentParent肯定为null
if (mContentParent == null) {
// TODO 第九 安装decorView
installDecor();
} else {
mContentParent.removeAllViews();
}
// TODO 第十二 将传入的layoutResID布局文件添加到mContentParent中.
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
// TODO 第九
private void installDecor() {
if (mDecor == null) {
// TODO 第十 创建decorView
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
}
if (mContentParent == null) {
// TODO 第十一 获取用来盛放 setContentView(R.layout.XXX) 中的布局文件的容器.
mContentParent = generateLayout(mDecor);
...
}
}
// TODO 第十
protected DecorView generateDecor() {
// 创建DecorView,它其实是一个FramLayout容器,下面会将一个布局放入这个容器中.
// 这个布局是Framwork层定义好的布局, 它有标题栏和内容栏,这两个是Framwork层给划分好的.
// 还记得当setContentView(R.layout.XXX)进来的一个布局么,
// 那个布局最终会被添加到内容栏中, 内容栏的id为android.R.id.content.
return new DecorView(getContext(), -1);
}
// TODO 第十一
protected ViewGroup generateLayout(DecorView decor) {
TypedArray a = getWindowStyle();
...
int layoutResource;
int features = getLocalFeatures();
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title_icons;
} else {
layoutResource = com.android.internal.R.layout.screen_title_icons;
}
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
layoutResource = com.android.internal.R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_custom_title;
} else {
layoutResource = com.android.internal.R.layout.screen_custom_title;
}
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title;
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}
} else {
layoutResource = com.android.internal.R.layout.screen_simple;
}
...
// 从上面的源码可以看出,layoutResource 这个布局文件是通过一系列的配置筛选出来的
// TODO 第十二 将系统layoutResource布局文件解析为View
View in = mLayoutInflater.inflate(layoutResource, null);
// TODO 第十三 将View加入到decorView中
// 上面讲过decroView其实是FramLayout, 然后系统layoutResource布局文件中有一个容器的id为android.R.id.content
// id为content的这个容器最终会用来放setContentView(R.layout.XXX)中的布局文件
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
// TODO 第十四 这里就是取出id为content的容器,将这个容器最终再返回去.
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
}
// Instrumentation.java
public class Instrumentation {
// TODO 第一
public Activity newActivity(ClassLoader cl, String className,Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
// TODO 第二
// 创建Activity对象
return (Activity)cl.loadClass(className).newInstance();
}
//TODO 第五
public void callActivityOnCreate(Activity activity, Bundle icicle) {
if (mWaitingActivities != null) {
...
// TODO 第六
//这里调用onCreate()方法
activity.onCreate(icicle);
...
}
}