在Android系统启动时,第一个启动起来的进程就是zygote进程,然后由zygote启动SystemServer,然后就是启动ActivityManagerService、WindowManagerService等系统核心服务,这些服务承担着整个Android系统与客户端交互的重担。zygote除了启动系统服务与进程外,普通的用户进程也由zygote进程fork而来,当一个应用进程启动起来后,就会加载用户在AndroidManifest.xml中配置的默认加载的Activity,此时加载的入口是ActivityThread.main(String[] args)方法,该方法类似于C语言中 的main方法,是整个应用程序的入口。
在ActivityThread.main(String[] args)方法中,主要的功能是创建Application和Activity,并且调用Activity的生命周期函数,如onCreate、onResume等。
#ActivityThread
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
//1.创建UI线程的Looper
Looper.prepareMainLooper();
//2.创建ActivityThread对象,但它并不是线程,是封装了UI线程消息循环与操作Activity生命周期的工具类
ActivityThread thread = new ActivityThread();
//3.调用ActivityThread的attach方法,这是核心方法,Application、Activity的创建入口就在这里
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
/// M: ANR Debug Mechanism
mAnrAppManager.setMessageLogger(Looper.myLooper());
//4.启动UI线程消息循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
#ActivityThread
//UI线程与Appliction关联
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
//
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//获取ActiivtyManagerService实例
final IActivityManager mgr = ActivityManager.getService();
try {
//6.注意这里,将mAppThread与Application进行管理
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// Watch for getting close to heap limit.
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
// Don't set application object here -- if the system crashes,
// we can't display an alert, we just want to die die die.
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
// add dropbox logging to libcore
DropBox.setReporter(new DropBoxReporter());
ViewRootImpl.ConfigChangedCallback configChangedCallback
= (Configuration globalConfig) -> {
synchronized (mResourcesManager) {
// We need to apply this change to the resources immediately, because upon returning
// the view hierarchy will be informed about it.
if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
null /* compat */)) {
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
// This actually changed the resources! Tell everyone about it.
if (mPendingConfiguration == null
|| mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
mPendingConfiguration = globalConfig;
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
}
}
}
};
ViewRootImpl.addConfigCallback(configChangedCallback);
}
从上述程序可以看到,在ActivityThread.main中主要的功能就是创建了UI线程消息循环,并启动了消息循环,最重要的是创建了ActivityThread,并调用了attach方法。在attach方法中又调用了ActivityManagerService中的attachApplication(mAppThread)方法,这个方法才是重点。mAppThread是ApplicationThread类型,它也不是一个Thread,而是一个Binder,负责与远程的ActivityManagerService进程交互。在了解attachApplication之前,先了解一下ApplicationThread与ActivityThread的关联。
public final class ActivityThread {
final ApplicationThread mAppThread = new ApplicationThread();
final Looper mLooper = Looper.myLooper();
final H mH = new H();
//通过mH发送消息
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
}
#ActivityThread内部类
//ApplicationThread 内部类,负责与ActivityManagerService交互
private class ApplicationThread extends IApplicationThread.Stub {
... ...
//向UI线程发送一个resume activity 的消息
public final void scheduleResumeActivity(IBinder token, int processState,
boolean isForward, Bundle resumeArgs) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "resumeActivity " + ActivityThread.this
+ " operation received seq: " + seq);
updateProcessState(processState, false);
sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0, 0, seq);
}
public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
ResultData res = new ResultData();
res.token = token;
res.results = results;
sendMessage(H.SEND_RESULT, res);
}
//发送启动Activity的消息
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
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;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
//向UI线程发送一个H.LAUNCH_ACTIVITY
sendMessage(H.LAUNCH_ACTIVITY, r);
}
... ...
}
//H是ActivityThread的内部类
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
//加载Activity
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case PAUSE_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
... ...
}
}
ApplicationThread与ActivityManagerService进行交互,通过H类的对象mH来发送消息,并且在H类的handleMessage函数中进行处理,然后handleMessage根据消息的类型调用ActivityThread中对应的方法。比如handleresumeActivity来使Activity变得可见。因为H的消息队列就是主线程的消息队列,因此,这些过程都在UI线程中处理。
#ActivityManagerServcie
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
//1.转到了attachApplicationLocked
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
//进程Record
ProcessRecord app;
//代码省略
if (app.instr != null) {
//2.ApplicationThread绑定Application
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(/*getGlobalConfiguration()*/getThemeConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);//panjuan add for GM22APF-765
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(/*getGlobalConfiguration()*/getThemeConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);//panjuan add for GM22APF-765
}
... ...
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
//3.调用StackSupervisor的attachApplicationLocked函数
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
// Find any services that should be running in this process...
... ...
return true;
}
以上代码中注释3处,才是真正启动Activity的地方。mStackSupervisor的类型为ActivityStackSupervisor,观察注释3处ActivityStackSupervisor 类中的attachApplicationLocked方法。
#ActivityStackSupervisor
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
... ...
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
//从栈中取出Activity
final ActivityStack stack = stacks.get(stackNdx);
if (!isFocusedStack(stack)) {
continue;
}
stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
//获取栈顶 ActivityRecord
final ActivityRecord top = stack.topRunningActivityLocked();
final int size = mTmpActivityList.size();
for (int i = 0; i < size; i++) {
final ActivityRecord activity = mTmpActivityList.get(i);
if (activity.app == null && app.uid == activity.info.applicationInfo.uid
&& processName.equals(activity.processName)) {
try {
//启动Activity
if (realStartActivityLocked(activity, app,
top == activity /* andResume */, true /* checkConfig */)) {
didSomething = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting activity "
+ top.intent.getComponent().flattenToShortString(), e);
throw e;
}
}
}
}
}
if (!didSomething) {
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
return didSomething;
}
... ...
}
在AttachApplicationLocked函数中会遍历整个Activity栈,并且找出栈顶ActivityStack,然后调用realStartActivityLocked 函数来真正启动Activity。
#ActivityStackSupervisor
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
if (!allPausedActivitiesComplete()) {
// While there are activities pausing we skipping starting any new activities until
// pauses are complete. NOTE: that we also do this for activities that are starting in
// the paused state because they will first be resumed then paused on the client side.
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"realStartActivityLocked: Skipping start of r=" + r
+ " some activities pausing...");
return false;
}
final TaskRecord task = r.getTask();
final ActivityStack stack = task.getStack();
beginDeferResume();
try {
r.startFreezingScreenLocked(app, 0);
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
r.app = app;
if (mKeyguardController.isKeyguardLocked()) {
r.notifyUnknownVisibilityLaunched();
}
// Have the window manager re-evaluate the orientation of the screen based on the new
// activity order. Note that as a result of this, it can call back into the activity
// manager with a new orientation. We don't care about that, because the activity is
// not currently running so we are just restarting it anyway.
if (checkConfig) {
final int displayId = r.getDisplayId();
final Configuration config = mWindowManager.updateOrientationFromAppTokens(
getDisplayOverrideConfiguration(displayId),
r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId);
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring
// configurations and trying to resume top activity of focused stack.
mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */,
displayId);
}
if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */,
true /* isTop */)) {
// We only set the visibility to true if the activity is allowed to be visible
// based on
// keyguard state. This avoids setting this into motion in window manager that is
// later cancelled due to later calls to ensure visible activities that set
// visibility back to false.
r.setVisibility(true);
}
final int applicationInfoUid =
(r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) {
Slog.wtf(TAG,
"User ID for activity changing for " + r
+ " appInfo.uid=" + r.appInfo.uid
+ " info.ai.uid=" + applicationInfoUid
+ " old=" + r.app + " new=" + app);
}
app.waitingToKill = null;
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
mService.updateLruProcessLocked(app, true, null);
mService.updateOomAdjLocked();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE",
false);
}
try {
if (app.thread == null) {
throw new RemoteException();
}
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
// We don't need to deliver new intents and/or set results if activity is going
// to pause immediately after launch.
results = r.results;
newIntents = r.newIntents;
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Launching: " + r + " icicle=" + r.icicle + " with results=" + results
+ " newIntents=" + newIntents + " andResume=" + andResume);
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId,
System.identityHashCode(r), task.taskId, r.shortComponentName);
if (r.isHomeActivity()) {
// Home process is the root process of the task.
mService.mHomeProcess = task.mActivities.get(0).app;
}
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
r.sleeping = false;
r.forceNewConfig = false;
mService.showUnsupportedZoomDialogIfNeededLocked(r);
mService.showAskCompatModeDialogLocked(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
ProfilerInfo profilerInfo = null;
if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
if (mService.mProfileProc == null || mService.mProfileProc == app) {
mService.mProfileProc = app;
ProfilerInfo profilerInfoSvc = mService.mProfilerInfo;
if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) {
if (profilerInfoSvc.profileFd != null) {
try {
profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup();
} catch (IOException e) {
profilerInfoSvc.closeFd();
}
}
profilerInfo = new ProfilerInfo(profilerInfoSvc);
}
}
}
app.hasShownUi = true;
app.pendingUiClean = true;
app.forceProcessStateUpTo(mService.mTopProcessState);
// Because we could be starting an Activity in the system process this may not go
// across a Binder interface which would create a new Configuration. Consequently
// we have to always create a new Configuration here.
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);
logIfTransactionTooLarge(r.intent, r.icicle);
//1.调用ActivityThread的scheduleLaunchActivity启动Activity
(app ——> ProcessRecord)
(app.thread ——> ProcessRecord.IApplicationThread)
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package
// manager will ensure that only activity can run in the main
// process of the .apk, which is the only thing that will be
// considered heavy-weight.
if (app.processName.equals(app.info.packageName)) {
if (mService.mHeavyWeightProcess != null
&& mService.mHeavyWeightProcess != app) {
Slog.w(TAG, "Starting new heavy weight process " + app
+ " when already running "
+ mService.mHeavyWeightProcess);
}
mService.mHeavyWeightProcess = app;
Message msg = mService.mHandler.obtainMessage(
ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
msg.obj = r;
mService.mHandler.sendMessage(msg);
}
}
} catch (RemoteException e) {
if (r.launchFailed) {
// This is the second time we failed -- finish activity
// and give up.
Slog.e(TAG, "Second failure launching "
+ r.intent.getComponent().flattenToShortString()
+ ", giving up", e);
mService.appDiedLocked(app);
stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"2nd-crash", false);
return false;
}
// This is the first time we failed -- restart process and
// retry.
r.launchFailed = true;
app.activities.remove(r);
throw e;
}
} finally {
endDeferResume();
}
r.launchFailed = false;
if (stack.updateLRUListLocked(r)) {
Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
}
if (andResume && readyToResume()) {
// As part of the process of launching, ActivityThread also performs
// a resume.
stack.minimalResumeActivityLocked(r);
} else {
// This activity is not starting in the resumed state... which should look like we asked
// it to pause+stop (but remain visible), and it has done so and reported back the
// current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to PAUSED: " + r + " (starting in paused state)");
r.state = PAUSED;
}
// Launch the new version setup screen if needed. We do this -after-
// launching the initial activity (that is, home), so that it can have
// a chance to initialize itself while in the background, making the
// switch back to it faster and look better.
if (isFocusedStack(stack)) {
mService.startSetupActivityLocked();
}
// Update any services we are bound to that might care about whether
// their client may have activities.
if (r.app != null) {
mService.mServices.updateServiceConnectionActivitiesLocked(r.app);
}
return true;
}
最终调用了ActivityThread中的内部类的ApplicationThread中的scheduleLaunchActivity函数。在该函数中会发送一个H.LAUNCH_ACTIVITY消息给UI线程。
public final class ActivityThread {
... ...
//内部类 ApplicationThread
private class ApplicationThread extends IApplicationThread.Stub {
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
//初始化代码
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;
r.overrideConfig = overrideConfig;
//更新配置
updatePendingConfiguration(curConfig);
//发送启动Activity的消息
sendMessage(H.LAUNCH_ACTIVITY, r);
}
}
... ...
}
ActivityThread的内部类H的handlMessage函数会处理该消息,然后会调用ActivityThread的handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason)函数,在这个函数中会创建将要启动的Activity,并且调用其生命周期函数onCreate、onResume。ApplicationThread 中的 scheduleLaunchActivity 函数的代码在上文中给出,下面是ActivityThread的handleLaunchActivity代码。
#ActivityThread中 handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
if (!ThreadedRenderer.sRendererDisabled) {
GraphicsEnvironment.earlyInitEGL();
}
WindowManagerGlobal.initialize();
//1.创建并且加载Activity,调用其onCreate函数。
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
//2.调用Activity的onResume方法,使得Activity变得可见。
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out paused, because it
// needs to be visible but isn't in the foreground. We accomplish this by going
// through the normal startup (because activities expect to go through onResume()
// the first time they run, before their window is displayed), and then pausing it.
// However, in this case we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just retain the current
// state it has.
performPauseActivityIfNeeded(r, reason);
// We need to keep around the original state, in case we need to be created again.
// But we only do this for pre-Honeycomb apps, which always save their state when
// pausing, so we can not have them save their state when restarting from a paused
// state. For HC and later, we want to (and can) let the state be saved as the
// normal part of stopping the activity.
if (r.isPreHoneycomb()) {
r.state = oldState;
}
}
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
#ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
//构建Context
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
//3. 创建Activity
activity = mInstrumentation.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);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
//4.创建Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
//获取Activity的title
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);
//5. Activity与Context、Application关联起来
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);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
//6.回调Activity的onCreate方法
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
//6.回调Activity的onCreate方法
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
//7.执行Activity的onStart方法
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
在调用ActivityThread的handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) 后调用performLaunchActivity(r, customIntent)函数来创建Activity,并且将Activity与Application关联上,然后调用Activity的onCreate、onStart函数。再之后调用handleResumeActivity函数。
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
... ...
... ...
}
#ActivityThread
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
return;
}
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
//1.最终调用Activity的onResume方法
r = performResumeActivity(token, clearHide, reason);
if (r != null) {
final Activity a = r.activity;
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManager.getService().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
//2.获取Activity的window
r.window = r.activity.getWindow();
//3.获取Window的DecorView,也就是最顶层视图。
View decor = r.window.getDecorView();
//4.将DecorView先隐藏
decor.setVisibility(View.INVISIBLE);
//5.获取WindowManager
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//6.将DecorView添加到窗口中
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r, false /* force */);
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
performConfigurationChangedForActivity(r, r.newConfig);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
+ r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig);
r.newConfig = null;
}
if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
+ isForward);
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
//7.使得Activity变得可见,其实是设置DecorView变为可见
r.activity.makeVisible();
}
}
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(
TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
// Tell the activity manager we have resumed.
if (reallyResume) {
try {
//8.最后通知ActivityManagerService,该activity已经变为resume状态
ActivityManager.getService().activityResumed(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
} else {
// If an exception was thrown when trying to resume, then
// just end this activity.
try {
ActivityManager.getService()
.finishActivity(token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
//真正执行Activity的onResume方法
#ActivityThread
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (localLOGV) Slog.v(TAG, "Performing resume of " + r
+ " finished=" + r.activity.mFinished);
if (r != null && !r.activity.mFinished) {
if (clearHide) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
}
try {
r.activity.onStateNotSaved();
r.activity.mFragments.noteStateNotSaved();
checkAndBlockForNetworkAccess();
if (r.pendingIntents != null) {
deliverNewIntents(r, r.pendingIntents);
r.pendingIntents = null;
}
if (r.pendingResults != null) {
deliverResults(r, r.pendingResults);
r.pendingResults = null;
}
//执行onResume方法
r.activity.performResume();
synchronized (mResourcesManager) {
// If there is a pending local relaunch that was requested when the activity was
// paused, it will put the activity into paused state when it finally happens.
// Since the activity resumed before being relaunched, we don't want that to
// happen, so we need to clear the request to relaunch paused.
for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
if (relaunching.token == r.token
&& relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
relaunching.startsNotResumed = false;
}
}
}
EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
r.paused = false;
r.stopped = false;
r.state = null;
r.persistentState = null;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to resume activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
}
return r;
}
handleReumeActivity函数又调用了performResumeActivty函数来回调Activity的onResume函数,并且DecorView添加到WindowManager中,最后将Activity的DecorView设置为可见,并且通知ActivityManagerService渲染视图,因此,在onResume函数之后,Activity就显示在屏幕上了。
在ActivityThread的main方法之后,会依次执行以下方法:
这就是一个典型的模板方法,ActivityThread的main函数被调用之后,依次执行Activity的onCreate、onStart、onResume函数,用户通常在Activity的子类中覆写onCreate方法,并且在其中调用setContentView方法来设置布局。从上文可以知道,在onResume之后,Activity的布局内容就显示到窗口上了。
#Activity
/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
实际上调用了mWindow的setContentView方法,Window的实现类是PhoneWindow,观察PhoneWindow的setContentView。
#PhoneWindow
public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
#PhoneWindow
@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) {
//1.生成DecorView
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 {
//2.将layoutResId的布局
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
//构建mDecor对象,并且初始化标题栏和Content Parent(我们要显示的内容区域)
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1); //3.构建DecorView
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//4.获取ContentView容器,即显示内容的区域
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
if (decorContentParent != null) {
mDecorContentParent = decorContentParent;
mDecorContentParent.setWindowCallback(getCallback());
if (mDecorContentParent.getTitle() == null) {
mDecorContentParent.setWindowTitle(mTitle);
}
final int localFeatures = getLocalFeatures();
for (int i = 0; i < FEATURE_MAX; i++) {
if ((localFeatures & (1 << i)) != 0) {
mDecorContentParent.initFeature(i);
}
}
mDecorContentParent.setUiOptions(mUiOptions);
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
(mIconRes != 0 && !mDecorContentParent.hasIcon())) {
mDecorContentParent.setIcon(mIconRes);
} else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
mIconRes == 0 && !mDecorContentParent.hasIcon()) {
if(!mIsStartingWindow){
mDecorContentParent.setIcon(
getContext().getPackageManager().getDefaultActivityIcon());
mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
}
}
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
(mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
mDecorContentParent.setLogo(mLogoRes);
}
// Invalidate if the panel menu hasn't been created before this.
// Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
// being called in the middle of onCreate or similar.
// A pending invalidation will typically be resolved before the posted message
// would run normally in order to satisfy instance state restoration.
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
invalidatePanelMenu(FEATURE_ACTION_BAR);
}
} else {
//设置Title等
mTitleView = findViewById(R.id.title);
if (mTitleView != null) {
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
final View titleContainer = findViewById(R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
mContentParent.setForeground(null);
} else {
mTitleView.setText(mTitle);
}
}
}
if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(mBackgroundFallbackResource);
}
// Only inflate or create a new TransitionManager if the caller hasn't
// already set a custom one.
if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
if (mTransitionManager == null) {
final int transitionRes = getWindowStyle().getResourceId(
R.styleable.Window_windowContentTransitionManager,
0);
if (transitionRes != 0) {
final TransitionInflater inflater = TransitionInflater.from(getContext());
mTransitionManager = inflater.inflateTransitionManager(transitionRes,
mContentParent);
} else {
mTransitionManager = new TransitionManager();
}
}
mEnterTransition = getTransition(mEnterTransition, null,
R.styleable.Window_windowEnterTransition);
mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
R.styleable.Window_windowReturnTransition);
mExitTransition = getTransition(mExitTransition, null,
R.styleable.Window_windowExitTransition);
mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
R.styleable.Window_windowReenterTransition);
mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
R.styleable.Window_windowSharedElementEnterTransition);
mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
USE_DEFAULT_TRANSITION,
R.styleable.Window_windowSharedElementReturnTransition);
mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
R.styleable.Window_windowSharedElementExitTransition);
mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
USE_DEFAULT_TRANSITION,
R.styleable.Window_windowSharedElementReenterTransition);
if (mAllowEnterTransitionOverlap == null) {
mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
R.styleable.Window_windowAllowEnterTransitionOverlap, true);
}
if (mAllowReturnTransitionOverlap == null) {
mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
R.styleable.Window_windowAllowReturnTransitionOverlap, true);
}
if (mBackgroundFadeDurationMillis < 0) {
mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
R.styleable.Window_windowTransitionBackgroundFadeDuration,
DEFAULT_BACKGROUND_FADE_DURATION_MS);
}
if (mSharedElementsUseOverlay == null) {
mSharedElementsUseOverlay = getWindowStyle().getBoolean(
R.styleable.Window_windowSharedElementsUseOverlay, true);
}
}
}
}
#PhoneWindow
protected DecorView generateDecor(int featureId) {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());//构建mDecorView对象
}
setContetnView的基本流程如下:
1.构建mDecor对象。mDecor就是整个窗口的顶层视图,它主要包含了Title和ContentView两个区域,Title的区域就是我们的标题栏,Content View区域就是显示xml布局内容中的区域。
2.设置一些关于关于窗口的属性,初始化标题栏区域和内容属性区域。
这里比较复杂的是generateDecor(mDecor) 函数,可以深入分析:
#PhoneWindow
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
//1.获取窗口的Style属性
TypedArray a = getWindowStyle();
//2.设置一些窗口属性等,代码省略
if (false) {
System.out.println("From style:");
String s = "Attrs:";
for (int i = 0; i < R.styleable.Window.length; i++) {
s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
+ a.getString(i);
}
System.out.println(s);
}
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
if (mIsFloating) {
setLayout(WRAP_CONTENT, WRAP_CONTENT);
setFlags(0, flagsToUpdate);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
}
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestFeature(FEATURE_ACTION_BAR);
}
if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
requestFeature(FEATURE_ACTION_BAR_OVERLAY);
}
if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
requestFeature(FEATURE_ACTION_MODE_OVERLAY);
}
if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
requestFeature(FEATURE_SWIPE_TO_DISMISS);
}
if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
}
if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
false)) {
setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
& (~getForcedWindowFlags()));
}
if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
false)) {
setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
& (~getForcedWindowFlags()));
}
if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
}
if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
}
if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch,
getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB)) {
setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));
}
a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString()
+ ", major: " + mMinWidthMajor.coerceToString());
if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
a.getValue(R.styleable.Window_windowFixedWidthMajor,
mFixedWidthMajor);
}
if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
a.getValue(R.styleable.Window_windowFixedWidthMinor,
mFixedWidthMinor);
}
if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
a.getValue(R.styleable.Window_windowFixedHeightMajor,
mFixedHeightMajor);
}
if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
a.getValue(R.styleable.Window_windowFixedHeightMinor,
mFixedHeightMinor);
}
if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {
requestFeature(FEATURE_CONTENT_TRANSITIONS);
}
if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {
requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
}
mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);
final Context context = getContext();
final int targetSdk = context.getApplicationInfo().targetSdkVersion;
final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
final boolean targetHcNeedsOptions = context.getResources().getBoolean(
R.bool.target_honeycomb_needs_options_menu);
final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
} else {
setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
}
if (!mForcedStatusBarColor) {
mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
}
if (!mForcedNavigationBarColor) {
mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
mNavigationBarDividerColor = a.getColor(R.styleable.Window_navigationBarDividerColor,
0x00000000);
}
WindowManager.LayoutParams params = getAttributes();
// Non-floating windows on high end devices must put up decor beneath the system bars and
// therefore must know about visibility changes of those.
if (!mIsFloating) {
if (!targetPreL && a.getBoolean(
R.styleable.Window_windowDrawsSystemBarBackgrounds,
false)) {
setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
}
if (mDecor.mForceWindowDrawsStatusBarBackground) {
params.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
}
}
if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
if (a.getBoolean(R.styleable.Window_windowLightNavigationBar, false)) {
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}
if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB) {
if (a.getBoolean(
R.styleable.Window_windowCloseOnTouchOutside,
false)) {
setCloseOnTouchOutsideIfNotSet(true);
}
}
if (!hasSoftInputMode()) {
params.softInputMode = a.getInt(
R.styleable.Window_windowSoftInputMode,
params.softInputMode);
}
if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
mIsFloating)) {
/* All dialogs should have the window dimmed */
if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
}
if (!haveDimAmount()) {
params.dimAmount = a.getFloat(
android.R.styleable.Window_backgroundDimAmount, 0.5f);
}
}
if (params.windowAnimations == 0) {
params.windowAnimations = a.getResourceId(
R.styleable.Window_windowAnimationStyle, 0);
}
// The rest are only done if this window is not embedded; otherwise,
// the values are inherited from our container.
if (getContainer() == null) {
if (mBackgroundDrawable == null) {
if (mBackgroundResource == 0) {
mBackgroundResource = a.getResourceId(
R.styleable.Window_windowBackground, 0);
}
if (mFrameResource == 0) {
mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
}
mBackgroundFallbackResource = a.getResourceId(
R.styleable.Window_windowBackgroundFallback, 0);
if (false) {
System.out.println("Background: "
+ Integer.toHexString(mBackgroundResource) + " Frame: "
+ Integer.toHexString(mFrameResource));
}
}
if (mLoadElevation) {
mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
}
mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
}
// Inflate the window decor.
//2.根据一些属性来选择不同的顶层视图布局,例如,设置了FEATURE_NO_TITLE的属性,那么就选择那个没有title区域的布局。layoutResource布局就是整个Activity的布局,其中包含有title的区域和content区域,content区域就是用来显示通过setContentView。设置进来的内容区域,也就是要显示的视图。
int layoutResource; //布局资源id
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
setCloseOnSwipeEnabled(true);
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
layoutResource = R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
// If no other features and not embedded, only need a title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
//加载顶层视图
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//6.获取到内容显示区域,这是一个ViewGroup类型,其实是FrameLayout
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
//6.设置一些背景、title等属性,代码省略
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
ProgressBar progress = getCircularProgressBar(false);
if (progress != null) {
progress.setIndeterminate(true);
}
}
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
registerSwipeCallbacks(contentParent);
}
// Remaining setup -- of background and title -- that only applies
// to top-level windows.
if (getContainer() == null) {
final Drawable background;
if (mBackgroundResource != 0) {
background = getContext().getDrawable(mBackgroundResource);
} else {
background = mBackgroundDrawable;
}
mDecor.setWindowBackground(background);
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
}
if (mTitleColor == 0) {
mTitleColor = mTextColor;
}
setTitleColor(mTitleColor);
}
mDecor.finishChanging(); //完成解析
return contentParent; //返回contentParent布局,而不是整个DecorView
}
#DecorView
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
mStackId = getStackId();
if (mBackdropFrameRenderer != null) {
loadBackgroundDrawablesIfNeeded();
mBackdropFrameRenderer.onResourcesLoaded(
this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
getCurrentColor(mNavigationColorViewState));
}
mDecorCaptionView = createDecorCaptionView(inflater);
//4.将layoutResource的内容添加到mDecor中
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
//4.将layoutResource的内容添加到mDecor中
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
// Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mContentRoot = (ViewGroup) root;
initializeElevation();
}
generateLayout步骤如下:
1.获取用户设置的一些属性和Flag。
2.根基一些属性选择不同的顶层视图布局,如FEATURE_NO_TITLE则选择没有title的布局文件等。
选择layoutResource = R.layout.screen_title;的情形来分析,首先看screen_title的布局代码。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
title显示区域
<FrameLayout
android:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
style="?android:attr/windowTitleBackgroundStyle">
<TextView android:id="@android:id/title"
style="?android:attr/windowTitleStyle"
android:background="@null"
android:fadingEdge="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
内容显示区域,例如:main_activity.xml的布局就会被放到这个ViewGroup下面。
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
我们可以看到两个区域,即title区域和content区域,generateLayout获取的是content区域,代码如下:
//1.获取到我们的内容显示区域,这是一个ViewGroup类型的,其实FrameLayout
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
获取的就是xml中id为content的FrameLayout,这个content就是内容显示区域。
这两个区域就组成了mDecor视图,我们的main_activity.xml的布局就会被放在内容视图区域的。
3.加载顶层布局文件,转化为View,将其添加到mDecor中。
4.获取内容视图容器Content Parent,即用于显示内容的区域。
5.设置一些背景图和title等。
经过这几步,我们就得到mContentParent,就是用来装载视图的ViewGroup,再回过头来看setContentView函数。
#PhoneWindow
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
// 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) {
//1.生成DecorView,并且根据窗口属性加载顶级视图布局。
//获取mContentParent、设置一些基本属性等。
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
mContentParent.addView(view, params);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
#PhoneWindow
@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) {
//1.生成DecorView,并且根据窗口属性加载顶级视图布局。
//获取mContentParent、设置一些基本属性等。
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 {
//2.将layoutResId加载到mContentParent中
//这里的layoutResId就是Activity的onCreate函数执行的布局id
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
实际上就是将layoutResId这个布局的视图附加到mContentParent中,这个layoutResId就是在onCreate中设置给Activity的那个资源id,也就是说google预先设置了一些布局资源,这些布局资源中有一个留给开发者设置窗口内容的区域,也就是content区域,我们通过setContentView设置的布局会添加到content布局中,这个content布局就是一个framelayout,因此它是一个ViewGroup。
ViewGroup从语义上来说是视图组,其继承自View类,它其实就是一个视图的容器。Android中通过ViewGroup组织管理子视图。在Activity启动时,通过onCreate函数让用户自己设置界面,系统将这个布局界面添加到一个内置的布局界面的content区域中,此时,DcroView就建立起来了。然后调用onStart函数,并且在调用onResume函数之后,将DecorView添加到WindowManager中,并且设置Activty可见,ActivityManager.getService().activityResumed(token);然后通知ActivityManagerService,该Activity已经变为了resume状态,使得系统可以渲染Activity的视图。
参考《Android源码设计模式》