当前位置: 首页 > news >正文

Activity启动流程要点

一、Activity启动流程 

  • Activity的启动流程一般是通过调用startActivity或者是startActivityForResult来开始的
  • startActivity内部也是通过调用startActivityForResult来启动Activity,只不过传递的requestCode小于0
  • Activity的启动流程涉及到多个进程之间的通讯这里主要是ActivityThread与ActivityManagerService之间的通讯
  • ActivityThread向ActivityManagerService传递进程间消息通过ActivityManagerNative,ActivityManagerService向ActivityThread进程间传递消息通过IApplicationThread。
  • ActivityManagerService接收到应用进程创建Activity的请求之后会执行初始化操作,解析启动模式,保存请求信息等一系列操作。
  • ActivityManagerService保存完请求信息之后会将当前系统栈顶的Activity执行onPause操作,并且IApplication进程间通讯告诉应用程序继承执行当前栈顶的Activity的onPause方法;(A到B界面,打开B那么A得先Pause)
  • ActivityThread接收到SystemServer的消息之后会统一交个自身定义的Handler对象处理分发;
  • ActivityThread执行完栈顶的Activity的onPause方法之后会通过ActivityManagerNative执行进程间通讯告诉ActivityManagerService,栈顶Actiity已经执行完成onPause方法,继续执行后续操作;
  • ActivityManagerService会继续执行启动Activity的逻辑,这时候会判断需要启动的Activity所属的应用进程是否已经启动,若没有启动则首先会启动这个Activity的应用程序进程(毕竟可以多进程);
  • ActivityManagerService会通过socket与Zygote继承通讯,并告知Zygote进程fork出一个新的应用程序进程,然后执行ActivityThread的main()方法;
  • 在ActivityThread.main方法中执行初始化操作,初始化主线程异步消息,然后通知ActivityManagerService执行进程初始化操作;
  • ActivityManagerService会在执行初始化操作的同时检测当前进程是否有需要创建的Activity对象,若有的话,则执行创建操作;
  • ActivityManagerService将执行创建Activity的通知告知ActivityThread,然后通过反射机制创建出Activity对象,并执行Activity的onCreate方法,onStart方法,onResume方法;
  • ActivityThread执行完成onResume方法之后告知ActivityManagerService onResume执行完成(新界面展示),开始执行栈顶Activity的onStop方法(这个老界面即将走入后台,新界面马上展示);
  • ActivityManagerService开始执行栈顶的onStop方法并告知ActivityThread;
  • ActivityThread执行真正的onStop方法(A调用stop)

二、Activity布局创建流程

主要代码:

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//Activity.onCreatesetContentView(R.layout.activity_main);
}

  1.  当ActivityManagerService接收到启动Activity的请求之后会通过IApplicationThread进程间通讯告知ApplicationThread并执行handleLauncherActivity方法;
  2. handleLauncherActivity方法内部调用了performLaunchActivity方法;
  3. performLaunchActivity方法里通过反射的机制创建的Activity,并调用了Activity的attach方法;
    1. 初始化了一些Activity的成员变量,主要是mWindow对象,并且mWindow的成员实例是PhoneWindow实例;
  4. performLaunchActivity调用mInstrumentation.callActivityOnCreate(activity, r.state);在里面调用performCreate方法,方法里实现onCreate的回调。从这儿开始走到OnCrete方法。
  5. 那么来第一行,super.onCreate()里面主要就是做一个初始化,并且之后会执行一个判断逻辑,若Activity的mCalled为false,则会抛出我们刚刚捕获的异常,那么这个mCalled成员变量是在什么时候被赋值的呢?好吧,就是在Activity的onCreate方法赋值的,所以我们在实现自己的Activity的时候只有调用了super.onCreate方法才不会抛出这个异常,反过来说,我们实现自己的Actiivty,那么一定要在onCreate方法中调用super.onCreate方法。
  6. 接下来是setContentView()方法。
  7. public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();
    }

    这个getWindow就是phoneWindow,在activity.attach初始化的

  8. phoneWindow.setContentView--->installerDector()--->执行mDecor = generateDecor();生成一个DecorView。判断mContentParent(此处第一次为空)

    if (mContentParent == null) {mContentParent = generateLayout(mDecor);}调用此方法
  9. generateLayout()方法里通过调用LayoutInflater.inflate方法来加载布局文件到内存中,关于LayoutInflater.inflater是如何加载布局文件的,并且,通过对代码的分析,我们发现PhoneWindow中的几个成员变量:mDector,mContentRoot,mContentParent的关系mDector --> mContentRoot --> mContentParent(包含)
  10. activity到phonewidow再到mDector --> mContentRoot --> mContentParent,activity就拥有了布局文件的引用

     知识点: 

 

  • Activity的展示界面的特性是通过Window对象来控制的;
  • 每个Activity对象都对应这个一个Window对象,并且Window对象的初始化在启动Activity的时候完成,在执行Activity的onCreate方法之前;
  • 每个Window对象内部都存在一个FrameLayout类型的mDector对象,它是Acitivty界面的root view;
  • Activity中的window对象的实例是PhoneWindow对象,PhoneWindow对象中的几个成员变量mDector,mContentRoot,mContentParent都是View组件,它们的关系是:mDector --> mContentRoot --> mContentParent --> 自定义layoutView
  • LayoutInflater.inflate主要用于将布局文件加载到内存View组件中,也可以设定加载到某一个父组件中;
  • 典型的Activity的onCreate方法中需要调用super.onCreate方法和setContentView方法,若不调用super.onCreate方法,执行启动该Activity的逻辑会报错,若不执行setContentView的方法,该Activity只会显示一个空页面。

三、Activity的布局绘制流程

从AMS调Activity的onResume到App进程的主线程,有关Activity onResume生命周期的第一个方法就是handleResumeActivity,mWindowManager是在Activity的attach方法中被创建的 ,在获取了Activity的Window相关参数之后执行了r.activity.makeVisible()方法。

  //ActivityService.java  
@Overridepublic void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {......//1.最后会调到Activity的onResumefinal ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);       ......final Activity a = r.activity;......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) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE);2.获取WindowManagerImpl对象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;ViewRootImpl impl = decor.getViewRootImpl();if (impl != null) {impl.notifyChildRebuilt();}}if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded = true;3.调用WindowManagerImpl的addView方法wm.addView(decor, l);} ......}if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {r.activity.makeVisible();}}......}.......}

Activity执行onResume之后再ActivityThread中执行Activity的makeVisible方法。

  • //Activity.java
    void makeVisible() {if (!mWindowAdded) {ViewManager wm = getWindowManager();//这里的ViewManager对象是通过getWindowManager()方法获取的。是在Activity的attach方法方法中初始化的wm.addView(mDecor, getWindow().getAttributes());mWindowAdded = true;}mDecor.setVisibility(View.VISIBLE);//将mDecor给显示到界面上
    }
    
  •  wm.addView(mDecor, getWindow().getAttributes()); addView这里面调用了mGlobal.addView(view, params, mDisplay, mParentWindow);而mGlobal为WindowManagerGlobal,在mGlobal.addView里调用了root.setView。(ViewRootImpl)

  • 在root.setView里调用了调用了requestLayout方法,调用执行重绘的请求

  • @Override
    public void requestLayout() {if (!mHandlingLayoutInLayoutRequest) {checkThread();//检查是否UI线程mLayoutRequested = true;scheduleTraversals();
    这里面调用performTraversals方法,
    从这个方法开始我们的View经过大小测量,位置测量,
    界面绘制三个逻辑操作之后就可以展示在界面中了。}
    }

  • performTraversals的相关内容如下(绘制界面)

  • View的绘制流程包含了测量大小,测量位置,绘制三个流程;

  • Activity的界面绘制是从mDecor即根View开始的,也就是从mDecor的测量大小,测量位置,绘制三个流程;

  • View体系的绘制流程是从ViewRootImpl的performTraversals方法开始的;

  • View的测量大小流程:performMeasure --> measure --> onMeasure等方法;

  • View的测量位置流程:performLayout --> layout --> onLayout等方法;

  • View的绘制流程:onDraw等方法;

  • View组件的绘制流程会在onMeasure,onLayout以及onDraw方法中执行分发逻辑,也就是在onMeasure同时执行子View的测量大小逻辑,在onLayout中同时执行子View的测量位置逻辑,在onDraw中同时执行子View的绘制逻辑;

  • Activity中都对应这个一个Window对象,而每一个Window对象都对应着一个新的WindowManager对象(WindowManagerImpl实例);

相关文章:

Activity启动流程要点

一、Activity启动流程 Activity的启动流程一般是通过调用startActivity或者是startActivityForResult来开始的startActivity内部也是通过调用startActivityForResult来启动Activity,只不过传递的requestCode小于0Activity的启动流程涉及到多个进程之间的通讯这里主…...

lua 计算第几周

需求 计算当前赛季的开始和结束日期,2024年1月1日周一是第1周的开始,每两周是一个赛季。 lua代码 没有处理时区问题 local const 24 * 60 * 60 --一整天的时间戳 local server_time 1716595200--todo:修改服务器时间 local date os.date("*t…...

负载均衡策略

...

海外网红营销新趋势:“快闪式”营销如何迅速提升品牌曝光度

在当今数字化时代,海外网红营销已成为品牌迅速触达全球消费者、提升品牌曝光度和刺激销售的重要手段。其中,“快闪式”营销以其独特的时效性、创意性和互动性,成为品牌与海外网红合作的新趋势。本文Nox聚星将和大家探讨如何利用海外网红的影响…...

速看!打造专属数字化能力模型的七大关键!

在数字化浪潮中,企业如何打造适应自身发展的数字化能力模型?这是许多企业面临的重要课题。今天,通过众多企业使用蚓链数字化生态解决方案实践总结,为大家分享至关重要的七大经验,助你开启数字化转型之旅! 1…...

青蛙跳台阶问题

本期介绍🍖 主要介绍:青蛙跳台阶问题,青蛙跳台阶与斐波那契数列的关系👀。 文章目录 1. 题目2. 递归解题思路3. 迭代解题思路 1. 题目 从前有一只青蛙他想跳台阶,有n级台阶,青蛙一次可以跳1级台阶&#xff…...

linux日常运维2

下载linux离线安装包---- 利用 Downloadonly 插件下载 RPM 软件包及其所有依赖包 1. 先找个可以上网的linux操作系统,这里是以centos7操作系统为例,如果要使用centos6就先安装一个centos6的系统,然后让他可以上网,后面步骤如下 a.…...

flink cdc mysql整理与总结

文章目录 一、业务中常见的需要数据同步的场景CDC是什么FlinkCDC是什么CDC原理为什么是FlinkCDC业务场景flink cdc对应flink的版本 二、模拟案例1.阿里云flink sql2.开源flink sql(单机模式)flink 安装安装mysql3.flink datastream 三、总结 提示:以下是本篇文章正文…...

【三维重建】ePnP

PnP问题应用与一下场景: 已知三维点和对应二维点以及相机相机内参数,可以获取相机外参。 我们介绍其中的一种算法:ePnP 算法流程 1、ePnP算法首先在世界坐标系内寻找4个控制点,记作 C 1 w , C 2 w , C 3 w , C 4 w C_1^w,C_2^w,…...

C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...

8、python基础知识图谱

...

智慧校园建设规划方案

在信息化浪潮的推动下,智慧校园的建设已成为教育现代化的必然趋势。以创新科技赋能教育,打造智慧校园,旨在提升教学品质,优化管理流程,增强学生体验。构建智慧校园需要具有前瞻性的规划方案,它将以教育为核…...

【深度学习实战—8】:基于MediaPipe的人脸检测

✨博客主页:王乐予🎈 ✨年轻人要:Living for the moment(活在当下)!💪 🏆推荐专栏:【图像处理】【千锤百炼Python】【深度学习】【排序算法】 目录 😺一、Med…...

OSCP学习,布置你的Kali Linux

为什么要写这篇文章? 我是一个OSCP学习者,以教促学。同时也能让各位入门的师傅们更好的了解OSCP这门课程。本人文笔不太好,如果有什么写的不对的地方,师傅们多多指正。 参考资料: OSCP 考试电子书 Linux Basics for…...

PWA离线优先策略:提升用户体验的关键步骤

Progressive Web Apps (PWA) 的离线优先策略是通过Service Worker和Cache API实现的,它允许在没有网络连接时仍然可以访问网站的部分或全部内容。 2500G计算机入门到高级架构师开发资料超级大礼包免费送! 1. 创建Service Worker注册文件(se…...

网页提示“非私密连接”是为什么?

网页提示“非私密连接”(英文提示可能是 "Your connection is not private" 或 "Your connection is not secure")主要是因为浏览器无法验证你正试图访问的网站的SSL/TLS证书,或者是证书存在问题,从而无法建立…...

[自动驾驶技术]-8 Tesla自动驾驶方案之硬件(AI Day 2022)

特斯拉在AI Day 2022先介绍了AI编译器,后面又介绍了Dojo的硬件软件,软件部分和AI编译器有部分重叠,本文介绍还是延用AI Day的思路,分为三部分:AI编译和推理,Dojo硬件,Dojo软件。 特斯拉车道检测…...

人力资源管理信息化系统如何支持企业开展管理诊断?

华恒智信人力资源顾问有限公司致力于帮助企业开展人力资源管理方面的各项提升改进工作,在长期的咨询工作中,最常听到企业提到的问题莫过于管理诊断方面的问题,事实上,很多企业在日常工作中,都意识到企业内部存在管理方…...

Cohere继Command-R+之后发布大模型Aya-23,性能超越 Gemma、Mistral 等,支持中文

前言 近年来,多语言大模型(MLLM)发展迅速,但大多数模型的性能依然存在显著差距,尤其是在非英语语言方面表现不佳。为了推动多语言自然语言处理技术的发展,Cohere团队发布了新的多语言指令微调模型家族——…...

身为UI设计老鸟,不学点3D,好像要被潮流抛弃啦,卷起来吧。

当前3D原则在UI设计中运用的越来越多,在UI设计中,使用3D元素可以为界面带来以下几个价值: 增强视觉冲击力:3D元素可以通过立体感和逼真的效果,为界面增添视觉冲击力,使得设计更加生动、吸引人,并…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...