frameworks 之 Activity添加View

news/2025/2/22 0:27:40/

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个主要步骤 就是 LaunchActivityItemResumeActivityItem

1 LaunchActivityItem

1.1 Activity 创建

LaunchActivityItem 的 又会调用 ActivityThreadhandleLaunchActivity 方法

	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 方法中

  1. 通过反射调用对应的 Activity
  2. 调用 Activity的 attach 方法创建phoneWindow
  3. 通过 callActivityOnCreate 执行 Activity的 onCreate方法
  4. 设置 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和 windowMangerImplactivity.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_CREATEr.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 方法

  1. 创建了 PhoneWindow
  2. 调用 phoneWindow的setWindowManager 方法 创建对应 WindowManagerImpl 对象。
  3. 将创建的WindowManagerImpl 赋值给 mWindowManager
final void attach(Context context, ActivityThread aThread...) {...// 初始化 PhoneWindowmWindow = 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并赋值给 mWindowManagermWindowManager = mWindow.getWindowManager();
}

1.3 DecorView 创建

执行了 Activity onCreate 方法后 ,我们就会对其调用 setContentView 将要显示的布局ID创建创建视图,setContentView 方法又会调用 phoneWindowsetContentView方法

	public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();}

phoneWindowsetContentView主要做了

  1. 判断 mContentParent 是否为空(放应用要显示的布局容器),为空的话 则调用 installDecor 方法,创建 DecorView 和 内容容器 mContentParent
  2. 调用 inflate 将布局加载到 mContentParent 布局容器中
	public void setContentView(int layoutResID) {// 如果contentview为空则加载decorViewif (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 方法主要逻辑

  1. 判断 mDecor 是否为空 ,为空的话调用 generateDecor 方法**(直接new DecorView),,并赋值**
  2. 判断 mContentParent 是否为空,为空的话 调用 generateLayout() 方法获取对应的容器.(里面会通过feature 加载对应的布局,然后获取R.id.content的控件),并返回。
  3. 根据属性 设置对应的标题。
	private void installDecor() {mForceDecorInstall = false;// 为空则创建 DecorViewif (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的viewgroupif (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 主要

  1. 获取一系列属性
  2. 调用 getLocalFeatures 生成对应的 features,根据获取到的属性获取对应的布局ID赋值到 layoutResource
  3. 调用 decorView 的 onResourcesLoaded 方法 inflage出对应的布局,并通过 addView添加到 decorView,赋值给对应的mContentRoot 属性
  4. 根据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 layoutif (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 layoutif (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.contentViewGroup 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 的 handleResumeActivityclient.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,"RESUME_ACTIVITY");Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}

handleResumeActivity 方法

  1. 从 ActivityClientRecord 取出 创建的 Activity,。将 decorView 设置为 INVISIBLE
  2. 将对应的 LayoutParams type 层级设置为 WindowManager.LayoutParams.TYPE_BASE_APPLICATION
  3. 调用 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 给ActivityClientRecordr.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();WindowManager.LayoutParams l = r.window.getAttributes();// 将 decor赋值给activitya.mDecor = decor;// 设置Activity的层级为applicationl.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中 会调用

  1. 创建对应的 ViewRootImpl
  2. 将对应参数添加到各自的数组中
  3. 调用 ViewRootImplsetVIew 开始执行添加视图的 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 和 tokenif (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;}}// 创建对应的 ViewRootImplViewRootImpl 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() 获取sessionroot = 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 thingstry {root.setView(view, wparams, panelParentView, userId);} catch (RuntimeException e) {// BadTokenException or InvalidDisplayException, clean up.if (index >= 0) {removeViewLocked(index, true);}throw e;}}}

这样完成了Activity View的加载。


http://www.ppmy.cn/news/1573723.html

相关文章

数智驱动:医学编程与建模技术在智慧医院AI建设中的创新与变革

一、引言 1.1 研究背景与意义 在信息技术飞速发展的数智化时代,医疗行业正经历着深刻变革,医院的发展模式也在不断转型升级。随着人口老龄化加剧、疾病谱的变化以及人们对医疗服务质量要求的日益提高,传统的医疗模式已难以满足社会的需求,智慧医院建设成为医疗行业发展的…

嵌入式学习(18)---Linux文件编程中的进程

一、进程的概念 进程:(用来描述 程序动态执行的过程&#xff0c;方便操作系统管理的) 进行中的程序 程序的一次执行过程 (内存 CPU) 程序的实例 程序 ----加载到内存----> 进程 应用场景: 实现并发 同一时刻 同时发生 并行 …

DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)

前言 在当今数字化时代&#xff0c;AI编程助手已成为提升开发效率的利器。DeepSeek作为一款强大的AI模型&#xff0c;凭借其出色的性能和开源免费的优势&#xff0c;成为许多开发者的首选。今天&#xff0c;就让我们一起探索如何将DeepSeek接入PyCharm&#xff0c;实现高效、智…

[零基础]:用PaddleNLP在4060单卡上实践大模型预训练技术

作者&#xff1a;算力魔方创始人/英特尔创新大使刘力 之前我们分享了《从零开始训练一个大语言模型需要投资多少钱》&#xff0c;其中高昂的预训练费用让许多对大模型预训练技术感兴趣的朋友望而却步。 应广大读者的需求&#xff0c;本文将手把手教您如何在单张消费级显卡上&…

【Python爬虫(18)】解锁验证码识别:Python爬虫进阶秘籍

【Python爬虫】专栏简介&#xff1a;本专栏是 Python 爬虫领域的集大成之作&#xff0c;共 100 章节。从 Python 基础语法、爬虫入门知识讲起&#xff0c;深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑&#xff0c;覆盖网页、图片、音频等各类数据爬取&#xff…

J3打卡——DenseNet模型实现鸟类分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 1.检查GPU import tensorflow as tf gpustf.config.list_physical_devices("GPU") if gpus:tf.config.experimental.set_memory_growth(gpus[0],Tru…

POI优化Excel录入

57000单词原始录入时间258S 核心代码: List<Word> wordBookList ExcelUtil.getReader(file.getInputStream()).readAll(Word.class);if (!CollectionUtil.isEmpty(wordBookList)) {for (Word word : wordBookList) {//逐条向数据库中插入单词wordMapper.insert(word);}…

RT-Thread+STM32L475VET6——ADC采集电压

文章目录 前言一、板载资源二、具体步骤1.打开CubeMX进行配置1.1 使用外部高速时钟&#xff0c;并修改时钟树1.2 打开ADC1的通道3&#xff0c;并配置为连续采集模式(ADC根据自己需求调整&#xff09;1.3 打开串口1.4 生成工程 2. 配置ADC2.1 打开ADC驱动2.2 声明ADC2.3 剪切stm…