一、概述
Activity作为Android四大组件之一,也是我们平时开发中使用的最多的组件,相信大家已经了解了它的基本使用,那么是否知道Activity的onCreate()、onStart()、onResume()方法是什么时候调用的呢?接下来就从源码角度来分析Activity的工作原理
二、从main()方法源码开始分析
我们知道每一个程序都有一个入口,类似于c语言中的入口是main()方法一样,Android中也有个main()方法,它就是ActivityThrea中的main()方法。
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// 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());
Security.addProvider(new AndroidKeyStoreProvider());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
从上面代码可以看出,首先初始化了Looper,这也解释了为什么我们在子线程中使用Handler不是创建Looper,因为系统已经帮我们实现了。接下来,创建ActivityThread对象,并且调用attach()方法。
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
} 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 = new ContextImpl();
context.init(getSystemContext().mPackageInfo, null, this);
Application app = Instrumentation.newApplication(Application.class, context);
mAllApplications.add(app);
mInitialApplication = app;
app.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
// add dropbox logging to libcore
DropBox.setReporter(new DropBoxReporter());
ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mPackages) {
// We need to apply this change to the resources
// immediately, because upon returning the view
// hierarchy will be informed about it.
if (applyConfigurationToResourcesLocked(newConfig, null)) {
// This actually changed the resources! Tell
// everyone about it.
if (mPendingConfiguration == null ||
mPendingConfiguration.isOtherSeqNewer(newConfig)) {
mPendingConfiguration = newConfig;
queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig);
}
}
}
}
public void onLowMemory() {
}
public void onTrimMemory(int level) {
}
});
}
final ApplicationThread mAppThread = new ApplicationThread();
从源码可以看出,因为system为false,所以首先获取ActivityManagerService对象,然后调用ActivityManagerService的attachApplication()方法。至于这里为什么说IActivityManager是ActivityManagerService,将会在第三节中提到。继续看ActivityManagerService的attachApplication()。
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
省略
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
省略
}
关于attachApplicationLocked方法的代码很多,真正启动Activity的就是上面几行代码。继续跟进去
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) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFrontStack(stack)) {
continue;
}
ActivityRecord hr = stack.topRunningActivityLocked(null);
if (hr != null) {
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting activity "
+ hr.intent.getComponent().flattenToShortString(), e);
throw e;
}
}
}
}
}
if (!didSomething) {
ensureActivitiesVisibleLocked(null, 0);
}
return didSomething;
}
遍历Activity栈,找到栈顶的Activity,从下面一个代码可以看出是startActivity了
realStartActivityLocked(hr, app, true, true)
继续跟进去
省略
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
}
省略
这里还只是看核心代码,从上文可以看出,调用app.thread的scheduleLaunchActivity方法,而这里的app.thread又是ApplicationThread,而ApplicationThread又是什么呢?其实它是ActivityThread的内部类,当调用ApplicationThread的scheduleLaunchActivity的时候,会通过Handler发送一个消息,这个Handler就是在ActivityThread中的H这个类,在H中处理又交给ActivityThread的方法来处理。OK,看源码。
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profileFile = profileName;
r.profileFd = profileFd;
r.autoStopProfiler = autoStopProfiler;
updatePendingConfiguration(curConfig);
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
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;
mH.sendMessage(msg);
}
}
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
省略
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
省略
}
}
return Integer.toString(code);
}
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");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
省略
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
if (r.profileFd != null) {
mProfiler.setProfiler(r.profileFile, r.profileFd);
mProfiler.startProfiling();
mProfiler.autoStopProfiler = r.autoStopProfiler;
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
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.
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
// 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;
}
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.paused = true;
}
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null);
} catch (RemoteException ex) {
// Ignore
}
}
}
从handleLaunchActivity()方法中,首先调用performLaunchActivity()方法创建Activity。
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);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
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 {
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) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
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;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
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;
}
从上面可以看出,先创建Activity、再创建Application,接着依次执行Activity的onCreate()、onStart()方法主要是调用Instrumentation类中的方法完成生命周期方法。再回到handleLaunchActivity(),再获取了Activity对象之后,又调用了handleResumeActivity()方法.
再看这个方法之前,我们首先要知道当执行onResume()方法完成了什么?相信大家都知道,就是Activity从不可见到可见状态。
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
boolean reallyResume) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
ActivityClientRecord r = performResumeActivity(token, clearHide);
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 = ActivityManagerNative.getDefault().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, 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;
}
从上面可以看出首先调用performResumeActivity(),接着就是完成一些使Activity可见的操作,比如获取DecorView,并条件到windowManager上等,这里就不详细说了。从这里我们就大致了解Activity启动过程。
三、从startActivity()源码开始分析
首先从Activity的startActivity()方法开始看,几种重载都是调用startActivityForResult()方法
@Override
public void startActivity(Intent intent, Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
startActivityForResult()如下:
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
将Activity的启动交给了Instrumentation
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
然后Activity的启动又交给了ActivityManagerNative.getDefault()
public abstract class ActivityManagerNative extends Binder implements IActivityManager
ActivityManagerNative是一个抽象类,它继承Binder、实现IActivityManager,因此是一个Binder,接着看getDefault()方法返回的是什么?
static public IActivityManager getDefault() {
return gDefault.get();
}
再看
public final class ActivityManagerService extends ActivityManagerNative
由此可以看出AMS是具体实现。
然后就是AMS.startActivity()了,之后就是ActivityStack和ActivitySupervisor之间方法的切换,最后在ActivitySupervisor的realStartActivityLocked()方法中真正启动,接下来的和第二节的类似了,就不重复分析了。
四、分析setContentView()
相信setContentView()这个方法大家熟悉不过了,就是给Activity设置布局,那么它的底层到底是怎么实现的呢?
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}
这里调用window的setContentView(),我们知道这里的window就是PhoneWindow,看源码
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
private void 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);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
if (mTitleView != null) {
mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
View titleContainer = findViewById(com.android.internal.R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
if (mContentParent instanceof FrameLayout) {
((FrameLayout)mContentParent).setForeground(null);
}
} else {
mTitleView.setText(mTitle);
}
} else {
mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
if (mActionBar != null) {
mActionBar.setWindowCallback(getCallback());
if (mActionBar.getTitle() == null) {
mActionBar.setWindowTitle(mTitle);
}
final int localFeatures = getLocalFeatures();
if ((localFeatures & (1 << FEATURE_PROGRESS)) != 0) {
mActionBar.initProgress();
}
if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
mActionBar.initIndeterminateProgress();
}
boolean splitActionBar = false;
final boolean splitWhenNarrow =
(mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
if (splitWhenNarrow) {
splitActionBar = getContext().getResources().getBoolean(
com.android.internal.R.bool.split_action_bar_is_narrow);
} else {
splitActionBar = getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowSplitActionBar, false);
}
final ActionBarContainer splitView = (ActionBarContainer) findViewById(
com.android.internal.R.id.split_action_bar);
if (splitView != null) {
mActionBar.setSplitView(splitView);
mActionBar.setSplitActionBar(splitActionBar);
mActionBar.setSplitWhenNarrow(splitWhenNarrow);
final ActionBarContextView cab = (ActionBarContextView) findViewById(
com.android.internal.R.id.action_context_bar);
cab.setSplitView(splitView);
cab.setSplitActionBar(splitActionBar);
cab.setSplitWhenNarrow(splitWhenNarrow);
} else if (splitActionBar) {
Log.e(TAG, "Requested split action bar with " +
"incompatible window decor! Ignoring request.");
}
// Post the panel invalidate for later; avoid application onCreateOptionsMenu
// being called in the middle of onCreate or similar.
mDecor.post(new Runnable() {
public void run() {
// Invalidate if the panel menu hasn't been created before this.
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!isDestroyed() && (st == null || st.menu == null)) {
invalidatePanelMenu(FEATURE_ACTION_BAR);
}
}
});
}
}
}
}
从源码可以看出,首先获取DecorView对象,然后将其传到generateLayout(mDecor)获取mContentParent,那么这个mContentParent是什么呢?其实就是我们设置的xml布局,mContentParent + titleView就是我们说的DecorView.至于generateLayout(mDecor)是如何完成的,这里就不详解了。再次回到PhoneWindow的setContentView(),接着执行mLayoutInflater.inflate(layoutResID, mContentParent),再获取了内容之后,就开始填充了。
OK,这篇博客就到这里了。