一文读懂ActivityThread

article/2025/11/5 6:02:36

ActivityThread是什么,是主线程吗?它是如何被创建的,以及它的作用又是什么呢?带着这些问题,我们一起来分析下ActivityThread。

全文分为以下几个部分,大家可根据需求阅读

文章目录

    • ActivityThread是什么
    • ActivityThread对象如何被创建的
      • system_server进程
      • App进程
    • ActivityThread的作用
      • 进程
      • Activity
      • Service
      • BroadcastReceiver
      • ContentProvider
    • 总结

ActivityThread是什么

ActivityThread是应用进程的初始化类,它的main()方法就是应用的入口方法,也就是说应用进程被创建后会调用ActivityThread.main()方法,关于这一点可以参考《Android App进程创建过程分析》中客户端发送创建进程和服务端响应创建进程内容。ActivityThread也是我们常说的主线程,但是这种描述不太准确,ActivityThread不是线程,只不过它是在运行在主线程(main)的main()方法中创建的对象,自然它也是运行在主线程中。只能说ActivityThread是主线程的一部分,但不并能代表主线程。我们从下面的profiler cpu usage图也能看出,ActivityThread.main()方法是在主线程(main)中调用的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N5zsEBak-1634819360670)(./thread_of_activity_thread.png)]

ActivityThread对象如何被创建的

 关于ActivityThread对象创建,分为两种情况:

  • system_server进程创建ActivityThread对象;
  • App进程创建ActivityThread对象;

system_server进程

 关于system_server进程(进程名为system_process)会创建ActivityThread对象,可能大家会有点疑惑,不过system_sever进程中确实存在ActivityThread对象的,这一点我们可以通过AS profiler工具验证。

在这里插入图片描述

既然知道system_server进程中存在ActivityThread对象,我们就来看下system_server进程中创建ActivityThread对象的过程。
在这里插入图片描述

从上面的时序图我们可以看到:在SystemServer.createSystemContext()方法中会调用ActivityThread静态方法systemMain(),得到ActivityThread对象,这个过程中也会创建Application对象,并调用其onCreate()方法。我们通过源码看下整个过程,首先看下SystemServer.createSystemContext()方法。

//frameworks\base\services\java\com\android\server\SystemServer.java
private void createSystemContext() {//得到ActivityThread对象,ActivityThread activityThread = ActivityThread.systemMain();//为mSystemContext变量赋值mSystemContext = activityThread.getSystemContext();mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);final Context systemUiContext = activityThread.getSystemUiContext();systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}

该方法比较简单,首先通过ActivityThread静态方法systemMain()得到ActivityThread对象,接着给mSystemContext变量赋值,然后设置Context主题。我们重点看下ActivityThread.systemMain()方法。

//frameworks\base\core\java\android\app\ActivityThread.java
@UnsupportedAppUsage
public static ActivityThread systemMain() {if (!ActivityManager.isHighEndGfx()) {ThreadedRenderer.disable(true);} else {ThreadedRenderer.enableForegroundTrimming();}//创建ActivityThread对象ActivityThread thread = new ActivityThread();//然后调用attach方法,注意传入的两个参数;//第一个参数表示是system_server进程,第二个参数表示system_server进程是第一个被创建的应用类进程。thread.attach(true, 0);return thread;
}/**
* @param system 用于标志是否是system_server进程调用的;
* @param startSeq 表示当前创建的是第几个app进程。
*/
private void attach(boolean system, long startSeq) {sCurrentActivityThread = this;mSystemThread = system;if (!system) {android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",UserHandle.myUserId());RuntimeInit.setApplicationObject(mAppThread.asBinder());final IActivityManager mgr = ActivityManager.getService();try {mgr.attachApplication(mAppThread, startSeq);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}//.....省略部分代码......} else {//system_server创建ActivityThread对应else语句android.ddm.DdmHandleAppName.setAppName("system_process",UserHandle.myUserId());try {mInstrumentation = new Instrumentation();mInstrumentation.basicInit(this);ContextImpl context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);//创建Application对象,然后调用它的onCreate()方法mInitialApplication = context.mPackageInfo.makeApplication(true, null);mInitialApplication.onCreate();} catch (Exception e) {throw new RuntimeException("Unable to instantiate Application():" + e.toString(), e);}}//.....省略部分代码......
}

在systemMain()方法中会创建ActivityThread对象,然后调用attach(true, 0),true表示是system_server进程,0表示system_server是第一个被创建的应用进程。在attach()方法中会创建Application对象,并调用onCreate方法,Application具体创建过程和生命周期方法调用大家可以参考上面的时序图自己跟下代码。

App进程

 对于普通App进程中会创建ActivityThread对象这一点,想必大家不会有什么疑问。我们同样可以通过AndroidStudio profiler工具验证,比如下面所示的setting应用。

在这里插入图片描述

 和system_server进程不同,普通App进程中ActivityThread对象的创建是从ActivityThread.main()方法开始的,我们看下main()方法的具体实现。

public static void main(String[] args) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");AndroidOs.install();CloseGuard.setEnabled(false);//初始化Environment,调用该方法后;Environment类方法(比如getExternalStorageState())才能正确的起作用Environment.initForCurrentUser();// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("<pre-initialized>");//创建主线程Looper,主线程Looper是不可退出的。Looper.prepareMainLooper();// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.// It will be in the format "seq=114"long startSeq = 0;if (args != null) {for (int i = args.length - 1; i >= 0; --i) {if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {startSeq = Long.parseLong(args[i].substring(PROC_START_SEQ_IDENT.length()));}}}//创建ActivityThread对象,然后调用attach()方法。ActivityThread thread = new ActivityThread();thread.attach(false, startSeq);//将ActivityThread的Handler变量mH赋值给类变量sMainThreadHandler.if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);//进入loop循环,如果Looper中MessageQueue中没有消息,则会一阻塞。Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");
}

main()方法主要做了以下几件事:

  • 初始化Environment;
  • 创建主线程Looper;
  • 创建ActivityThread对象,并调用其attach()方法;
  • 调用Looper.loop(),进入循环,阻塞式等待消息。

和systemMain()一样,main()方法也会调用attach()方法,只不过传入的参数不一样,main()方法中第一参数传入的为false,整个流程如下时序图所示:

在这里插入图片描述

从时序图中我们可以看出,attach()方法执行过程中会调用ActivityManagerService.attachApplicationLocked()方法,该方法执行过程可分为以下几个步骤:

  • 创建Application对象,并调用其onCreate()生命周期方法;
  • 判断是否需要启动Activity(对应通过start activity 的方式冷启动App);
  • 判断是否需要启动Service(对应通过start service 的方式冷启动App);
  • 判断是否有广播接收者需要接收广播(对应通过send broadcast 的方式冷启动App);

整个过程也很好解释了为什么冷启动一个App时会先调用Application的生命周期方法。我们简单看下ActivityManagerService.attachApplicationLocked()方法。

//ActivityManagerService.java
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,int pid, int callingUid, long startSeq) {ProcessRecord app;long startTime = SystemClock.uptimeMillis();long bindApplicationTimeMillis;if (pid != MY_PID && pid >= 0) {synchronized (mPidsSelfLocked) {app = mPidsSelfLocked.get(pid);}//省略部分代码......}//省略部分代码......try{//省略部分代码......checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");bindApplicationTimeMillis = SystemClock.elapsedRealtime();mAtmInternal.preBindApplication(app.getWindowProcessController());final ActiveInstrumentation instr2 = app.getActiveInstrumentation();if (app.isolatedEntryPoint != null) {//如果是isolate进程(可通过android:isolatedProcess设置),则不绑定Applicationthread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);} else if (instr2 != null) { //下面两种情况会调用ActivityThread.ApplicationThread.bindApplication()thread.bindApplication(processName, appInfo, providers,instr2.mClass,profilerInfo, instr2.mArguments,instr2.mWatcher,instr2.mUiAutomationConnection, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.compat, getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions);} else {thread.bindApplication(processName, appInfo, providers, null, profilerInfo,null, null, null, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.compat, getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions);}if (profilerInfo != null) {profilerInfo.closeFd();profilerInfo = null;}// Make app active after binding application or client may be running requests (e.g// starting activities) before it is ready.app.makeActive(thread, mProcessStats);checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");mProcessList.updateLruProcessLocked(app, false, null);checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();} catch (Exception e) {// todo: Yikes!  What should we do?  For now we will try to// start another process, but that could easily get us in// an infinite loop of restarting processes...Slog.wtf(TAG, "Exception thrown during bind of " + app, e);app.resetPackageList(mProcessStats);app.unlinkDeathRecipient();mProcessList.startProcessLocked(app, new HostingRecord("bind-fail", processName));return false;}// Remove this record from the list of starting applications.mPersistentStartingProcesses.remove(app);if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,"Attach application locked removing on hold: " + app);mProcessesOnHold.remove(app);boolean badApp = false;boolean didSomething = false;// 判断是否需要启动Activity,当冷启动某个app的Activity的情况下,就会在此时启动Activity。if (normalMode) {try {didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());} catch (Exception e) {Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);badApp = true;}}// 判断是否需要启动Service,当通过start service的方式冷启动一个app时,会在此时启动serviceif (!badApp) {try {didSomething |= mServices.attachApplicationLocked(app, processName);checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");} catch (Exception e) {Slog.wtf(TAG, "Exception thrown starting services in " + app, e);badApp = true;}}// 判断是否有广播接收者,情况和上面Activity、Service类似。if (!badApp && isPendingBroadcastProcessLocked(pid)) {try {didSomething |= sendPendingBroadcastsLocked(app);checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");} catch (Exception e) {// If the app died trying to launch the receiver we declare it 'bad'Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);badApp = true;}}// Check whether the next backup agent is in this process...if (!badApp && backupTarget != null && backupTarget.app == app) {if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,"New app is backup target, launching agent for " + app);notifyPackageUse(backupTarget.appInfo.packageName,PackageManager.NOTIFY_PACKAGE_USE_BACKUP);try {thread.scheduleCreateBackupAgent(backupTarget.appInfo,compatibilityInfoForPackage(backupTarget.appInfo),backupTarget.backupMode, backupTarget.userId);} catch (Exception e) {Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);badApp = true;}}if (badApp) {app.kill("error during init", true);handleAppDiedLocked(app, false, true);return false;}//省略部分代码......return true;
}

attachApplicationLocked()方法很长,我们只截取了其中的一部分;在这个方法中首先会调用ApplicationThread.bindApplication()方法,在该方法中通过主线程Handler对象H发送绑定Application的消息,在消息处理方法handleBindApplication创建Application对象,并调用其onCreate()生命周期方法。当然在handleBindApplication()方法中不仅仅是创建Application对象和调用其生命周期方法,还包括设置进程的名称、应用data数据存储路径、时间格式等。在之后的流程就是判断是否需要启动Activity、Service、处理广播。

 了解完ActivityThread对象是如何被创建的,我们在来看下它具体有哪些作用。

ActivityThread的作用

进程

  ActivityThread对于App进程来说,它是App的入口。此外ActivityThread还实现了创建主线程Looper、dump应用内存使用情况、获取应用包名等接口;具体内容这里不展开,大家可以自己去看看。我们看看ActivityThread对于四大组件的作用,一句话概括,ActivityThread管理着四大组件的生命周期方法的调用。

Activity

 在之前的《Android Activity启动过程分析》有提到Activity生命周期方法的具体调用过程,所以这里不在赘述。Activity的几个生命周期方法的调用过程如下:

onCreate: ActivityThread.handleLaunchActivity() -> ActivityThread.performLaunchActivity() -> Instrumentation.callActivityOnCreate() -> Activity.performCreate(icicle) -> Activity.onCreate()

onStart: ActivityThread.handleStartActivity() -> ActivityThread.performStart() -> Instrumentation.callActivityOnStart() -> Activity.onStart()

onResume: ActivityThread.handleResumeActivity() -> ActivityThread.performResumeActivity() -> Activity.performResume() -> Instrumentation.callActivityOnResume() -> Activity.onResume()

onPause: ActivityThread.handlePauseActivity() -> ActivityThread.performPauseActivity() -> ActivityThread.performPauseActivityIfNeeded() -> Instrumentation.callActivityOnPause() -> Activity.performPause() -> Activity.onPause()

onStop: ActivityThread.handleStopActivity() -> ActivityThread.performStopActivityInner() -> ActivityThread.callActivityOnStop() -> Activity.performStop() -> Activity.onStop()

onDestory: ActivityThread.handleDestroyActivity() -> ActivityThread.performDestroyActivity() -> Instrumentation.callActivityOnDestroy() -> Activity.performDestroy() -> Activity.onDestroy()

对于Service、BroadcastReceiver以及ContentProvider的生命周期方法调用具体细节,这里也不展开,下次再对她们一一单独讲解,这里只列举调用过程。

Service

onCreate: ActivityThread.scheduleCreateService() -> ActivityThread.handleCreateService() -> Service.onCreate()

onBind(): ActivityThread.scheduleBindService() -> ActivityThread.handleBindService() -> Service.onBind()

onStartCommand: ActivityThread.scheduleServiceArgs() -> ActivityThread.handleServiceArgs() -> Service.onStartCommand()

onDestroy: ActivityThread.scheduleStopService() -> ActivityThread.handleStopService() -> Service.onDestroy()

BroadcastReceiver

onReceive: ActivityThread.ApplicationThread.scheduleReceiver() -> ActivityThread.handleReceiver() -> Receiver.onReceive()

ContentProvider

onCreate: ActivityThread.ApplicationThread.scheduleInstallProvider() -> ActivityThread.handleInstallProvider() -> ActivityThread.installContentProviders() -> ActivityThread.installProvider() -> ContentProvider.attachInfo() -> ContentProvider.onCreate()

总结

 最后我们稍稍总结下

  • ActivityThread类是应用初始化类,它的main()方法是应用的入口方法;
  • ActivityThread不是线程,我们之所以称它为“主线程”,是因为它运行在主线程中;
  • ActivityThread负责创建Application对象以及管理其生命周期方法调用;
  • ActivityThread管理着四大组件的生命周期方法调用;

最后,留给大家一个作业——为什么四大组件的的生命周期方法是在主线程中被调用的?大家可以带着这个问题自己去研究下ActivityThread。另外,关于Activity的启动和App进程的创建可以参考以下的文章

Activity UI显示流程分析

Android Activity启动过程分析

Android App进程创建过程分析


http://chatgpt.dhexx.cn/article/3gJJUiUH.shtml

相关文章

Android ActivityThread(主线程或UI线程)简介

1. ActivityThread功能 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数)&#xff0c;并根据AMS的要求&#xff08;通过IApplicationThread接口&#xff0c;AMS为Client、ActivityThread.ApplicationThread为Server&#xff09;负责调度和执行activities、broa…

ActivityThread的理解和APP的启动过程

ActivityThread的理解和APP的启动过程 ActivityThreadActivityThread的初始化主线程Looper的初始化主线程Handler的初始化ApplicationThread及Activity的创建和启动 APP的启动系统的启动过程APP的启动过程APP启动过程的部分代码思考 总结 ActivityThread ActivityThread就是我…

validate中remote返回函数中+号导致submitHandler无法执行

validate中remote返回函数中号导致submitHandler无法执行 这是2017年以来我遇到的最无语的bug&#xff0c;现在暂时还没想到原因&#xff0c;但是这个错误真的很无语。 这是我的validate中rule的定义&#xff0c;其中 new Date; 采用至慕课网上validate插件视频中的例子。 rul…

jQuery(六)插件、Validate验证提交表单、submitHandler、更改错误信息显示的位置、required、Validator、内置验证方式表、validate ()的可选项汇总

jQuery&#xff08;六&#xff09;插件、Validate验证提交表单、submitHandler、更改错误信息显示的位置、required、Validator、内置验证方式表、validate ()的可选项汇总 文章目录 jQuery&#xff08;六&#xff09;插件、Validate验证提交表单、submitHandler、更改错误信息…

ajax post 不起作用,jQuery验证submitHandler在$ .ajax post表单数据中不起作用

我使用$.ajax发送数据并使用jQuery验证插件进行验证&#xff0c;如下所示&#xff1a; Send JS&#xff1a; jQuery(document).ready(function ($) { $(#myform).validate({ rules: { name: { required: true, rangelength: [4, 20], }, }, submitHandler: function (form) { $…

FileReader()用法

FileReader()用法HTML5定义了FileReader作为文件API的重要成员用于读文件&#xff0c;根据W3C的定义&#xff0c;FileReaderr接口提供了读取文件的方法和包含读取 结果的事件模型。 FileReader的方法使用比较简单&#xff0c;可以按照以下步骤创建FileReader对象并调用其他的方…

read/write/fsync与fread/fwrite/fflush的关系和区别

read/write/fsync&#xff1a; 1. linux底层操作&#xff1b; 2. 内核调用&#xff0c; 涉及到进程上下文的切换&#xff0c;即用户态到核心态的转换&#xff0c;这是个比较消耗性能的操作。 fread/fwrite/fflush&#xff1a; 1. c语言标准规定的io流操作&#xff0c;建立…

FileReader详解

我在Google Chrome Web Store上发布了一个案例hahaOCR&#xff0c;该扩展程序可以帮助用户识别出图片中的文字信息&#xff0c;并以文本形式显示&#xff0c;大家可以在chrome网上应用商店中找到我发布的应用程序&#xff0c;如图所示&#xff1a; 图1 - hahaOCR 该扩展程序支持…

f.readlines()

f.readlines() ftext open(1299_wangyifei_edit.pinyin, r, encodingutf-8)lines ftext.readlines()print("lines",lines)l ftext.readlines()print("l",l)输出结果&#xff1a; 原因&#xff1a; readlines() 方法用于读取所有行(直到结束符 EOF)并返…

FileReader的用法

FileReader是一种异步文件读取机制&#xff0c;结合input:file可以很方便的读取本地文件。 input:file input的file类型会渲染为一个按钮和一段文字。点击按钮可打开文件选择窗口&#xff0c;文字表示对文件的描述&#xff08;大部分情况下为文件名&#xff09;&#xff1b;…

【原创】通过 ioctl + FIONREAD 判定数据可读

【原创】通过 ioctl FIONREAD 判定数据可读 摩云飞 2016-05-12 09:57:51 浏览470 评论0 libevent ioctl FIONREAD 摘要&#xff1a; 在排查业务 bug 的过程中&#xff0c;看到如下两种输出信息&#xff1a; TCP 连接正常情况下&#xff0c;进行数据读取 14:00:38 epoll_ctl…

fread函数详解

文章迁移&#xff1a; fread函数详解 - 码到城攻fread函数详解&#xff0c;C函数使用注意事项&#xff0c;freadhttps://www.codecomeon.com/posts/93/ 函数原型&#xff1a; size_t fread( void *buffer, size_t size, size_t count, FILE *stream ) buf…

SQLSTATE: Insert value list does not match column list: 1136 Column count doesn‘t match value count

使用thinkphp5的insertAll的批量新增函数&#xff0c;提示SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesnt match value count at row 2 其意思就是&#xff1a;在第二行数据开始&#xff0c;插入的&#xff0c;每行数据的值的个数和…

Column-Stores vs. Row-Stores: How Different Are They Really

概述 从论文的标题可以看出这篇论文不是陈述一种新的技术、架构&#xff0c;而更偏议论文一点&#xff0c;它主要的目的在于搞清楚对于分析类的查询为什么Column-Store比Row-Store好那么多&#xff1f;好在哪里&#xff1f;一般认为原因是: 分析类查询往往只查询一个表里面很少…

Android应用开发之( TableLayout中stretchColumns、shrinkColumns的用法)

从字面上来看&#xff0c;TableLayout也比较简单&#xff0c;关键是要对相关的属性要熟悉&#xff0c;先看一个简单的例子&#xff08;后面为效果图&#xff09;&#xff1a; <?xml version"1.0" encoding"utf-8"?> <TableLayout xmlns:android…

CollenctionList

1.Collection集合 1.1集合体系结构【记忆】 集合类的特点 提供一种存储空间可变的存储模型&#xff0c;存储的数据容量可以随时发生改变 集合类的体系图 1.2Collection集合概述和基本使用【应用】 Collection集合概述 是单例集合的顶层接口&#xff0c;它表示一组对象&#xff…

输入界面,关于stretchColumns和selectAllOnFocus的属性设置

这是整个TableLayout的代码&#xff1a; <TableLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:orientation"vertical"android:layout_width"fill_parent&qu…

android:stretchcolumns=0,1,2,3,stretch_stretch是什么意思

stretch是什么意思 stretch是伸展、可伸缩的意思。具体释义如下&#xff1a; stretch英 [stretʃ] 美 [strɛtʃ] 1、动词 v.伸展;延伸;持续;包括 例&#xff1a;It is better to stretch the tight muscles first 最好先伸展一下僵硬的肌肉。 2、名词 n.伸展;弹性;一片;一…

StretchBlt()函数使用

StretchBlt函数从源矩形中复制一个位图到目标矩形&#xff0c;必要时按目前目标设备设置的模式进行图像的拉伸或压缩。 说白了功能就是缩放。 函数原型如下 函数原型&#xff1a;BOOL StretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeig…

STL_set/multiset

STL_set/multiset 简介&#xff1a;本文主要介绍STL中的&#xff0c;set与multiset的使用&#xff0c;只需要把本文的代码自己敲完便可学会。 set容器的基本概念 注意&#xff1a;set容器没有push_back, pop_back这两种插入接口&#xff0c;只能用insert函数进行插入 如果向s…