首先我们要知道,Android程序的主入口是 ActivityThread 的 main函数中,所有应用程序 有且仅有一个ActivityThread.
public static void main(String[] args) { // ..... // ..... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); // ....... Looper.loop(); }
上面省略了一部分代码,只看我们关注的即可.
可以看到,在main函数里, 为我们创建了个Looper. 并且new 了一个ActivityThread, 接着调用 ActivityThread 的attach(false) 方法.
private void attach(boolean system) { ....... if(!system){ //非系统应用 final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { // Ignore } } }
可以看到,上面代码与 AmS(ActivityManagerService) 进行了关联. 这里有人就想了, 为什么要关联呢 ?
实际,由名字我们可以看出,AmS就是管理我们Activity的, 与之对应的还有 WmS(WindowManagerService)负责显示窗口到界面上,这里我们不讨论它..
当我们启动APP时, AmS会 调用ApplicationThread的 bindApplication() 然后通过H (extends Handler)类 来传递给ActivityThread 的 handleBindApplicaiont().
public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) { .......... .......... AppBindData data = new AppBindData(); //构建Application 的Data对象 data.processName = processName; data.appInfo = appInfo; data.providers = providers; data.instrumentationName = instrumentationName; data.instrumentationArgs = instrumentationArgs; data.instrumentationWatcher = instrumentationWatcher; data.instrumentationUiAutomationConnection = instrumentationUiConnection; data.debugMode = debugMode; data.enableOpenGlTrace = enableOpenGlTrace; data.restrictedBackupMode = isRestrictedBackupMode; data.persistent = persistent; data.config = config; data.compatInfo = compatInfo; data.initProfilerInfo = profilerInfo; sendMessage(H.BIND_APPLICATION, data); //发送消息 至 ActivityThread. }
case BIND_APPLICATION: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); AppBindData data = (AppBindData)msg.obj; handleBindApplication(data); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
接下来我们看 handleBindApplication(data)
private void handleBindApplication(AppBindData data) { try { //在这之前,data.info还是空值 data.info = getPackageInfoNoCheck(data.appInfo,data.compatInfo); ....... Application app = data.info.makeApplication(data.restrictedBackupMode, null); } }
可以看到, 这里调用到了 data.info.makeApplication(), 其内创建了ContextImpl 和 Application 我们来看代码~
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { if (mApplication != null) { return mApplication; } Application app = null; try { java.lang.ClassLoader cl = getClassLoader(); // 获取classLoader ..... ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); //创建ContextImpl app = mActivityThread.mInstrumentation.newApplication( //创建Application cl, appClass, appContext); appContext.setOuterContext(app); } catch (Exception e) { ....... } .... mApplication = app if(instrumentation!=null){ instrumentation.callApplicationOnCreate(app); //调用Application onCreate } }
以上步骤就是创建Application的过程...
当我们要启动某个Activity时, AmS会调用 scheduleLaunchActivity, 之后会通过 H 发送消息 至ActivityThread 调用 handleLaunchActivity.
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { ....... ActivityClientRecord r = new ActivityClientRecord(); // 构建记录Activity 信息类 //客户端activity,可以通过该token 通知AmS当前运行的Activity的状态. r.token = token; r.ident = ident; r.intent = intent; r.referrer = referrer; r.voiceInteractor = voiceInteractor; r.activityInfo = info; r.compatInfo = compatInfo; r.state = state; r.persistentState = persistentState; r.pendingResults = pendingResults; r.pendingIntents = pendingNewIntents; r.startsNotResumed = notResumed; r.isForward = isForward; r.profilerInfo = profilerInfo; updatePendingConfiguration(curConfig); sendMessage(H.LAUNCH_ACTIVITY, r); //发送消息. }
发送消息后会调用 handleLaunchActivity, 在其内部, 会调用peformLaunchActivity,然后创建一个Activity.
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ......... ........ Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( // newActivity cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state != null) { r.state.setClassLoader(cl); } } }
可以看到这里利用了classLoader 来创建了一个Activity, 创建好Activity 之后 会调用到 Activity的attach方法,在attach方法内部进行一些 变量的赋值,并设置baseContext.
if (activity != null) { Context appContext = createBaseContextForActivity(r, 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); }
接下来就会调用 activity的 performCreate方法,最终会调用 onCreate方法,然而我们在自己的 Activity里 重写到了onCreate. 有没有很熟悉的感觉~~~
接下来到我们自己 的onCreate中,一般我们都会在super.oncreate()后 写上setContentView(int layoutId).
public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }
@Override public void setContentView(int layoutResID) { // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { mLayoutInflater.inflate(layoutResID, mContentParent); } final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } }
由上可以看到, 会进入installDecor方法 。
if (mDecor == null) { mDecor = generateDecor(); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } } if (mContentParent == null) { mContentParent = generateLayout(mDecor);</span> ....... }
这里面主要是 generateDecor()方法 和 generateLayout方法.
generateDecor (); 内部创建一个DecorView,该类为 PhoneWindow内部类, 继承至FrameLayout,实际上 它就是我们的根布局. 在generateLayout内部, 会给decorview 加上一个修饰窗口, 修饰窗口可以理解为我们的标题栏, 之后会找到 id为ID_ANDROID_CONTENT 并强转成ViewGroup 该ViewGroup就是 mContentParent.
接下来回到setContentView 方法内,这时 mContentParent 被成功赋值. 接下来会调用mLayout.inflate(layoutResId,mContentParent), 将你自己的布局加入到mContenetParent中.
到此为止我们的窗口就填充完毕了, 接下来我们要去给显示出来.
当Activity准备完成后, 会通知AmS, 之后会进行一系列的调用, 最终调用到 Activity的makeVisible()方法. 添加就是从这里开始的.
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
可以看到 这里我们getWindowManager, 它返回的是Activity的 mWindowManager常亮,是在 attach方法内赋值的,而实现了WindowManager的 类是WindowManagerImpl, 但是WindowManagerImpl内部真正操作的类却是 WindowManagerGlobal. So~ 这里wm.addView 实际上是调用了 WindowManagerGlobal的addView, 下面我们来看看该方法.
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { // 检查参数有效性 if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (display == null) { throw new IllegalArgumentException("display must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } .......省略一些代码 // 查看窗口类型数值 是否在 1000~ 1999之间, 这之间的值 都为子窗口,如果是则遍历找出该窗口的父窗口.</span> if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { final int count = mViews.size(); for (int i = 0; i < count; i++) { if (mRoots.get(i).mWindow.asBinder() == wparams.token) { panelParentView = mViews.get(i); } } } // 构建ViewRootImpl root = new ViewRootImpl(view.getContext(), display); // 给view设置布局参数 view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams);</span> // do this last because it fires off messages to start doing things try { //通过 root.setview将 view显示到手机窗口中. root.setView(view, wparams, panelParentView); }
可以看到 ,最后创建了ViewRootImpl, 并且给view设置参数, 并且把ViewRootImpl, view, wparams 分别加入三个集合中. 然后调用root,setView, 在setView内 最终会调用 res.mWindowSession.addToDisPlay()从而通知WmS加入该窗口.
以上,就是显示窗口的步骤.