frameworks 之 Activity添加View
- 1 LaunchActivityItem
- 1.1 Activity 创建
- 1.2 PhoneWindow 创建
- 1.3 DecorView 创建
- 2 ResumeActivityItem
讲解 Activity加载View的时机和流程
涉及到的类如下
- frameworks/base/core/java/android/app/Activity.java
- frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
- frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
- frameworks/base/core/java/android/view/WindowManagerImpl.java
从之前文章Activity启动流程可知,最终会到 ActivityTaskSupervisor 的 realStartActivityLocked 方法,而 realStartActivityLocked 最终会执行 2个主要步骤 就是 LaunchActivityItem 和 ResumeActivityItem。
1 LaunchActivityItem
1.1 Activity 创建
LaunchActivityItem 的 又会调用 ActivityThread的 handleLaunchActivity 方法
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = client.getLaunchingActivity(token);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
handleLaunchActivity 又会调用 performLaunchActivity 方法
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
return a;
}
performLaunchActivity 方法中
- 会通过反射调用对应的 Activity
- 调用 Activity的 attach 方法创建phoneWindow
- 通过 callActivityOnCreate 执行 Activity的 onCreate方法
- 设置 ActivityClientRecord 状态为 ON_CREATE
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
ContextImpl appContext = createBaseContextForActivity(r);
// 进行反射创建对应的 Activity对象
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
appContext.getAttributionSource());
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 (activity != null) {
...
// 调用 attach方法创建对应的的phoneView和 windowMangerImpl
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, r.shareableActivityToken);
...
r.activity = activity;
// 触发Activity的 onCreate方法
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
// 设置 ActivityRecord状态为 ON_CREATE
r.setState(ON_CREATE);
} 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;
}
1.2 PhoneWindow 创建
查看上面 Attach 方法
- 创建了 PhoneWindow
- 调用 phoneWindow的setWindowManager 方法 创建对应 WindowManagerImpl 对象。
- 将创建的WindowManagerImpl 赋值给 mWindowManager
final void attach(Context context, ActivityThread aThread...) {
...
// 初始化 PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
// 初始化 并设置WindowManager到phoneWindow对应的变量
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());
}
// 将上一步通过 setWindowManager 创建WindowManagerImpl并赋值给 mWindowManager
mWindowManager = mWindow.getWindowManager();
}
1.3 DecorView 创建
执行了 Activity onCreate 方法后 ,我们就会对其调用 setContentView 将要显示的布局ID创建创建视图,setContentView 方法又会调用 phoneWindow的setContentView方法
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
phoneWindow的setContentView主要做了
- 判断 mContentParent 是否为空(放应用要显示的布局容器),为空的话 则调用 installDecor 方法,创建 DecorView 和 内容容器 mContentParent
- 调用 inflate 将布局加载到 mContentParent 布局容器中
public void setContentView(int layoutResID) {
// 如果contentview为空则加载decorView
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);
}
...
}
其中 installDecor 方法主要逻辑
- 判断 mDecor 是否为空 ,为空的话调用 generateDecor 方法**(直接new DecorView),,并赋值**
- 判断 mContentParent 是否为空,为空的话 调用 generateLayout() 方法获取对应的容器.(里面会通过feature 加载对应的布局,然后获取R.id.content的控件),并返回。
- 根据属性 设置对应的标题。
private void installDecor() {
mForceDecorInstall = false;
// 为空则创建 DecorView
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);
}
// 为空则获取 decorView 用布局加载好里面的id为content的viewgroup
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
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);
}
}
}
}
}
generateLayout 主要
- 获取一系列属性
- 调用 getLocalFeatures 生成对应的 features,根据获取到的属性获取对应的布局ID赋值到 layoutResource
- 调用 decorView 的 onResourcesLoaded 方法 inflage出对应的布局,并通过 addView添加到 decorView,赋值给对应的mContentRoot 属性。
- 根据mDecorView获取ID为 R.id.content的内容容器,并返回出去
protected ViewGroup generateLayout(DecorView decor) {
...
// 获取设置一系列属性
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
...
// Inflate the window decor.
// 获取对应的 layout布局文件
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
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.onResourcesLoaded(mLayoutInflater, layoutResource);
// 根据mDecorView获取ID为 R.id.content
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
...
return contentParent;
}
2 ResumeActivityItem
经过 onCreate 视图view都创建准备好后,就会进入 resume阶段
ResumeActivityItem 又会执行对应的 handleResumeActivity 方法。
public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
// 执行 ActivityThread 的 handleResumeActivity
client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
handleResumeActivity 方法
- 从 ActivityClientRecord 取出 创建的 Activity,。将 decorView 设置为 INVISIBLE,
- 将对应的 LayoutParams type 层级设置为 WindowManager.LayoutParams.TYPE_BASE_APPLICATION
- 调用 phoneWindow 创建的 WindowManagerImpl(attach创建) ,调用 addView 将 decorView添加到 WMS中。
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
...
final Activity a = r.activity;
...
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) {
willBeVisible = ActivityClient.getInstance().willActivityBeVisible(
a.getActivityToken());
}
if (r.window == null && !a.mFinished && willBeVisible) {
// 赋值 phoneWindow 给ActivityClientRecord
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
// 将 decor赋值给activity
a.mDecor = decor;
// 设置Activity的层级为application
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
...
// 将decorView 通过 wms添加到容器中
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
}
}
}
WindowManagerImpl 添加时候 又会调用 全局单例WindowManagerGlobal 添加
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyTokens(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
addView中 会调用
- 创建对应的 ViewRootImpl
- 将对应参数添加到各自的数组中
- 调用 ViewRootImpl 的 setVIew 开始执行添加视图的 3步曲 (addToDisplayAsUser, relayout, finishDraw)
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
// 如果不为空则认为子窗口添加,通过 adjustLayoutParamsForSubWindow 补全对应的参数 如title 和 token
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
// 创建对应的 ViewRootImpl
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
// 从 mViews 获取该view是否已添加
int index = findViewLocked(view, false);
if (index >= 0) {
// 判断该view是否在移除
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
// 创建viewRootImpl,该方法会通过 WindowManagerGlobal.getWindowSession() 获取session
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, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
这样完成了Activity View的加载。