Activity
所有的生命周期方法调用都是在ActivityThread
类中执行的。
比如Activity
的onCreate
生命周期:
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
final Activity a = performLaunchActivity(r, customIntent);
return a;
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
//通过反射得到activity对象。
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
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,
r.assistToken);
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
return activity;
}
最后在Instrumentation
类中执行callActivityOnCreate
方法,callActivityOnCreate
方法中,执行Activity
中的performCreate
方法,最后执行onCreate
方法。
可以在ActivityThread
中找到Activity
其他生命周期方法:
handleStartActivity
handleResumeActivity
-
handlePauseActivity
等等。
Activity的onCreate
启动Activity
首先执行onCreate
方法,也就是刚刚performLaunchActivity
方法,在performLaunchActivity
方法中,在执行callActivityOnCreate
之前也就是执行Activity
的onCreate
方法之前先执行了Activity
的attach()
方法。
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
setAutofillOptions(application.getAutofillOptions());
}
在attach
方法中创建了PhoneWindow
,并执行了setWindowManager
方法,
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
mWindow
是PhoneWindow
。
这个方法设置的是WindowManagerImpl
类。
记住这一点
-- 海绵宝宝
setContentView()
在Activity
方法中执行setContentView
方法
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
海绵宝宝上面说getWindow
就是PhoneWindow
,
所以就是调用PhoneWindow
的setContentView
方法:
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);
}
最后一行,是将传入的布局id
加载到mContentParent
中,在第一行中,首先会判断mContentParent
是否是空,如果是null
进入到installDecor
方法中,先看一下这个方法都在做什么操作:
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
}
上面方法会创建一个DecorView
和mContentParent
,
进入到generateLayout
方法中:
protected ViewGroup generateLayout(DecorView decor) {
int layoutResource;
layoutResource = R.layout.screen_simple;
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
return contentParent;
}
layoutResource
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<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" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
执行DecorView
的onResourcesLoaded
方法:
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
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));
}
}
根据布局id
,将View
添加到DecorView
中。
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
这个就是我们布局当中的FrameLayout
。
这样我们就把我们的布局View
添加到了系统的FrameLayout
中。
总结:
在
ActivityThread
的handleLaunchAcitivity
方法进入到performLaunchActivity
方法,performLaunchActivity
方法进行实例化Activity
,并执行Activity
的attach
方法和onCreate
方法,其中attach
方法实例化了PhoneWindow
,和设置了WindowManagerImpl
。
执行完attach
方法之后执行onCreate
方法中的setContentView
方法,调用PhoneWindow
的setContentView
方法,在setContentView
方法中,实例化了DecorView
和然后将我们的系统布局添加到了DecorView
中,然后根据id
找到FrameLayout
,最后将用户的布局文件放到FrameLayout中
。
流程图
结构图
等等好像没有ViewRootImpl
什么关系:
在ActivityThread
的handleResumeActivity
方法:
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
final Activity a = r.activity;
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) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
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);
}
}
}
最后执行wm.addView(decor, l)
,海绵宝宝说这个是wm
是WindowManagerImpl
类,decor
就是DecorView
,进入WindowManagerImpl
的addView
方法:
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
从WindowMangerImpl
调用WindowManagerGlobal
的addView
方法:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
ViewRootImpl root;
synchronized (mLock) {
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
在此方法中会实例化ViewRootImpl
,并将decorView
传入到ViewRootIpml
的setView
方法中。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
//view就是decorview
mView = view;
requestLayout();
//设置decorview的父布局为viewrootImpl
view.assignParent(this);
}
在设置decorview
的父布局为viewrootImpl
之前执行requestLayout
方法:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
在此方法里面会做检查线程的操作然后执行scheduleTraversals()
:
void scheduleTraversals() {
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
最后在performTraversals
方法里面会执行DecorView
的测量布局和绘制。