AMS 和 Activity 组件沟通方式

AMS 和 Activity 组件沟通方式,第1张

ActivityRecord:Activity 在 AMS中的存在形式

创建的位置:

executeRequest()

ActivityStarterjava services\core\java\com\android\server\wm

我们注意到这里有一个 intent,调用方就通过这个intent 来启动目标Activity。

在ActivityRecord 的构造方法中,就通过这个intent 来创建了内部成员 appToken。这个appToken 很关键!

appToken 是一个类型为Token 的 成员变量, Token 是ActivityRecord的静态内部类,和普通的内部类不一样,这个静态内部类产生的对象不会默认持有外部类对象的引用。作用就相当于一个外部类,放在内部可读性更高。

Token 实现了 IApplicationTokenStub,可见它是一个Binder服务端。创建Activity时,

system_server进程 的 AMS服务通过调用scheduleLaunchActivity()将appToken传递到App进程。这样,客户端的就能持有ActivityRecord 的弱引用啦

这个类的组成也很简单,成员有三个

另外还有一个静态方法来获取这个ActivityRecord。

啥是弱引用?

在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。就是说如果这个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集。

它的代理端是传给谁呢?什么时候传过去的呢?

在创建这个Activity的时候传过去的,传给ActivityThread,通过ClientTransaction 这种方式

里面有一个成员变量

它在哪里创建?

继承自 WindowToken 类,WindowToken类就是 AMS 和 WMS 的通信

WindowToken是窗口管理器中一组相关窗口的容器。 通常这是一个 AppWindowToken,它是用于显示窗口的 Activity 的句柄。 对于嵌套窗口,会为父窗口创建一个 WindowToken 来管理其子窗口。

ActivityThread 继承自 ClientTransactionHandler

ClientTransactionHandler 是一个虚类,主要是定义了一些方法让子类ActivityThread重写。

ActivityThread 有一个类型为 ApplicationThread 的内部成员 mAppThread,在构造函数调用之前就初始化好了。

直接看它的源码,可以看出它是一个Binder服务端,没有默认的无参构造方法,所以系统会默认给它送一个。既然作为Binder服务端,那么肯定有Binder客户端,它的客户端就是AMS,ApplicationThread 是APP 和 AMS 沟通的桥梁~

继续看它是怎么绑定,怎么发送到AMS里面的。

调用main方法后,会new一个类型为ActivityThread的thread对象,然后调用ActivityThread的成员函数attach,最终会走到 AMS的attachApplication

在AMS中,拿到的是ApplicationThread 的客户端,最终会调用到这个binder对象的成员函数 bindApplication,把一些初始的参数传给它,比如Configuration 等,然后 Application 将这些参数保存进一个类型为 AppBindData的对象中,然后通过 外部类 ActivityThread 的 成员 mH ,一个Handler,通知ActivityThread 一个 BIND_APPLICATION 这样的消息。

处理逻辑是:

handleBindApplication,这里就不细讲了,大意是将参数保存下来,做一些初始化的 *** 作。创建 Instrumentation,通过这个Instrumentation 创建一个Application 对象,然后调用它的onCreate()

WindowProcessController

// 在WMS端驱动进程状态的控制器。

ClientTransaction 机制

本文将对Activity的工作过程进行分析。

主要学习以下内容:

(1)系统内部是如何启动一个Activity的

(2)新Activity的对象是何时创建的

(3)Activity的各个生命周日是被系统何时回调的

Activity启动流程分两种,一种是启动正在运行的app的Activity,即启动子Activity。如无特殊声明默认和启动该activity的activity处于同一进程。如果有声明在一个新的进程中,则处于两个进程。另一种是打开新的app,即为Launcher启动新的Activity。后边启动Activity的流程是一样的,区别是前边判断进程是否存在的那部分。

Activity的启动流程整体如下:

一Activity启动阶段

(一)涉及到的概念

进程:Android系统为每个APP分配至少一个进程

IPC:跨进程通信,Android中采用Binder机制。

(二)涉及到的类

ActivityStack:Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。

ActivitySupervisor:管理 activity 任务栈

ActivityThread:ActivityThread 运行在UI线程(主线程),App的真正入口。

ApplicationThread:用来实现AMS和ActivityThread之间的交互。

ApplicationThreadProxy:ApplicationThread 在服务端的代理。AMS就是通过该代理与ActivityThread进行通信的。

IActivityManager:继承与IInterface接口,抽象出跨进程通信需要实现的功能

AMN:运行在server端(SystemServer进程)。实现了Binder类,具体功能由子类AMS实现。

AMS:AMN的子类,负责管理四大组件和进程,包括生命周期和状态切换。AMS因为要和ui交互,所以极其复杂,涉及window。

AMP:AMS的client端代理(app进程)。了解Binder知识可以比较容易理解server端的stub和client端的proxy。AMP和AMS通过Binder通信。

Instrumentation:仪表盘,负责调用Activity和Application生命周期。测试用到这个类比较多。

(三)涉及到的进程

(1)Launcher所在的进程

(2)AMS所在的SystemServer进程

(3)要启动的Activity所在的app进程

如果是启动根Activity,就涉及上述三个进程。

如果是启动子Activity,那么就只涉及AMS进程和app所在进程。

(四)具体流程

Launcher:Launcher通知AMS要启动activity。

startActivitySafely->startActivity->InstrumentationexecStartActivity()(AMPstartActivity)->AMSstartActivity

AMS:PMS的resoveIntent验证要启动activity是否匹配。如果匹配,通过ApplicationThread发消息给Launcher所在的主线程,暂停当前Activity(即Launcher)。

暂停完,在该activity还不可见时,通知AMS,根据要启动的Activity配置ActivityStack。然后判断要启动的Activity进程是否存在

存在:发送消息LAUNCH_ACTIVITY给需要启动的Activity主线程,执行handleLaunchActivity

不存在:通过socket向zygote请求创建进程。进程启动后,ActivityThreadattach

判断Application是否存在,若不存在,通过LoadApkmakeApplication创建一个。在主线程中通过threadattach方法来关联ApplicationThread。

在通过ActivityStackSupervisor来获取当前需要显示的ActivityStack。

继续通过ApplicationThread来发送消息给主线程的Handler来启动Activity (handleLaunchActivity)。

handleLauchActivity:调用了performLauchActivity,里边Instrumentation生成了新的activity对象,继续调用activity生命周期。

IPC过程:

双方都是通过对方的代理对象来进行通信。

1app和AMS通信:app通过本进程的AMP和AMS进行Binder通信

2AMS和新app通信:通过ApplicationThreadProxy来通信,并不直接和ActivityThread通信

(五)参考函数流程

Activity启动流程(从Launcher开始):

第一阶段: Launcher通知AMS要启动新的Activity(在Launcher所在的进程执行)

第二阶段:AMS先校验一下Activity的正确性,如果正确的话,会暂存一下Activity的信息。然后,AMS会通知Launcher程序pause Activity(在AMS所在进程执行)

第三阶段:pause Launcher的Activity,并通知AMS已经paused(在Launcher所在进程执行)

第四阶段:检查activity所在进程是否存在,如果存在,就直接通知这个进程,在该进程中启动Activity;不存在的话,会调用Processstart创建一个新进程(执行在AMS进程)

第五阶段: 创建ActivityThread实例,执行一些初始化 *** 作,并绑定Application。如果Application不存在,会调用LoadedApkmakeApplication创建一个新的Application对象。之后进入Loop循环。(执行在新创建的app进程)

第六阶段:处理新的应用进程发出的创建进程完成的通信请求,并通知新应用程序进程启动目标Activity组件(执行在AMS进程)

第七阶段: 加载MainActivity类,调用onCreate声明周期方法(执行在新启动的app进程)

从另一个角度下图来概括:

下面简要介绍一下启动的过程:

        Step 1 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerServicestartActivity接口; 

        Step 2 ActivityManagerService调用ActivityStackstartActivityMayWait来做准备要启动的Activity的相关信息;

        Step 3 ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerServicestartActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;

        Step 4 ApplicationThread不执行真正的启动 *** 作,它通过调用ActivityManagerServiceactivityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;

        Step 5 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;

        Step 6 ActivityManagerServic调用ApplicationThreadscheduleLaunchActivity接口,通知相应的进程执行启动Activity的 *** 作;

        Step 7 ApplicationThread把这个启动Activity的 *** 作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。

创建Activity的步骤 

1 新建一个Android工程,起名为ActivityTest   将自动创建一个Activity选项勾选去掉 File-New-Android Application—图1

设置Application Name,PackageName点击Next-图2

将Create activity选项去掉,如上图,点击Next,Next,Finish

2 在Src文件中创建一个包,起名为comexampleactivitytest,此包名与图1中包名一致。

在包下新建一个class类,起名为Activity01 图3

在src中点击右键,New—Package—图4,

在包设置中,填写包名称,点击Finish。图5

在包上点击右键,New-Class

2 填写Activity名称。点击Finish。

3 在源文件中Activity01继承Activity,并复写onCreate方法(使用Alt+/导航键,使用Source/override method)

在创建好的文件中,使Activity01 extends Activity, 在提示中选择    Import androidappActivity

在Activity类中点击右键,选择source—Override/Implement Methods,选择onCreate(Bundle),点击ok

4 在AndroidManifestxml文件中注册Activity,并设置为MainActivity。   打开AndroidManifestxml文件

在<application></application>中添加<activity></activity>

<activity

android:name="comtestactivityActivity01"             android:label="myFirstActivity" >  <intent-filter>

<action android:name="androidintentactionMAIN"></action>

<category android:name="androidintentcategoryLAUNCHER"></category> </intent-filter>  </activity>

<intent-filter></intent-filter>过滤器将此Activity设置为首选项。 此时可运行程序,查看Activity的界面,界面空白。

5 在布局文件中设置简单的Button控件、EditText控件、 ViewText控件。   选择res—layout—右键—New Android xml文件

填入File名称—Finish。 在布局文件中添加控件

6 在源文件中使用setContentView函数,引用布局文件资源。  在Activity01java文件中添加代码

7 在源文件中通过findViewById函数来引用控件,并执行相应的text改变。

8 运行程序,观察效果。

Activity的使用:

(1)通过调用startActivity(intent)启动Activity,intent用来准确的描述你要启动的Activity,或者你要进行的action,intent也可以用来携带小数据给被启动Acitivity。

当在同一个应用中间需要简单启动另一个Activity,intent明确的定义你要启动Activity类即可:

[java] view plain copy

//定义一个intent,指名要启动的activity:ToStartActivity

Intent intent =  new Intent(MainActivitythis,ToStartActivityclass);

//使用startActivity(),启动activity

startActivity(intent);

在你的应用程序需要执行一些自身没有Activity可以执行的行为时,我们可以使用手机上的其他应用程序的Activity来代替执行。比如发送一个mail、查看一张、搜索一个单词等等。这个里也就是Intent的重要指出,你可以定义一个intent描述你想要做的行为,等你发送给系统后,系统会启动合适的Acitivty帮你执行,如果有多个应用的Activity都可以处理此行为时,系统会让用户去选择一个。

[java] view plain copy

//跨应用从google界面搜索

Intent intent = new Intent(IntentACTION_WEB_SEARCH);

intentputExtra(SearchManagerQUERY, "zy");

startActivity(intent);

当夸应用启动Activity时,在定义intent时必须要为他指定具体的acitvity,前提是此activity必须暴露在自己应用程序之外(android:exported="true"):

[java] view plain copy

Intent intent = new Intent();

//指定要启动组建完整的包名,对象名

ComponentName cn = new ComponentName("comandroidsettings",

"comandroidsettingsRunningServices");

intentsetComponent(cn);

// 使用contextstartActivity()时需要新启一个任务

intentaddFlags(IntentFLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

(2)通过调用 startActivityForResult(intent),来接收到启动的Acitivity反馈的结果。为了接收接下来启动的Activity的结果,需要重写onActivityResult()这个回调函数。当调用的activity完成后,它将返回一个含有结果的intent给onActivityResult()处理。比如,在应用程序的Activity中,需要用户选择联系人中的一个,Activity需要得到联系人的部分信息:

[java] view plain copy 

Intent intent = new Intent(IntentACTION_PICK,

ContactsPeopleCONTENT_URI);

//启动一个带有选择联系人返回结果的activity

startActivityForResult(intent, PICK_CONTACT_REQUEST);

这里的PICK_CONTACT_REQUEST为自定义的int型请求反馈结果代码。

[java] view plain copy 

//重新onActivityResult()用来处理接收到的返回结果

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

// 如果请求requestCode成功,且请求返回的结果resultCode是我们要的PICK_CONTACT_REQUEST  

if (resultCode == ActivityRESULT_OK

&& requestCode == PICK_CONTACT_REQUEST) {

// 处理Intent返回的数据,在联系人数据库中查找联系人的名字

Cursor cursor = getContentResolver()query(datagetData(),

new String[] { ContactsPeopleNAME }, null, null, null);

if (cursormoveToFirst()) { // 如果cursor不为空,就查找出联系人的名字  

int columnIndex = cursorgetColumnIndex(ContactsPeopleNAME);

String name = cursorgetString(columnIndex);

//添加其他功能

这里在要说明是onActivityResult()使用来处理返回结果的,首先要检查的是请求是否成功,然后是否有返回结果,结果是否是startActivityForResult()中所要的,如果满足,则处理通过Intent返回的数据。

4关闭Activity:

(1)Activity可以调用finish()方法关闭自己,也可以通过调用finishActivity()的方法关闭一个独立的之前启动的Activity。

调用finish()方法关闭自己:

[java] view plain copy

//关闭Activity

finish();

(2)调用finishActivity()的方法关闭一个独立的之前启动的Activity

[java] view plain copy

//此方法用在关闭使用startActivityForResult(requestCode)启用的Activity

thisfinishActivity(requestCode);

关于何时关闭一个Activity,一般由系统直接为我们管理。但是当你确认用户不用返回到此Activity时,我们调用以上方法关闭对应的Activity。

以上就是关于AMS 和 Activity 组件沟通方式全部的内容,包括:AMS 和 Activity 组件沟通方式、全面解析Activity: Activity的工作过程、简述activity的创建和使用步骤等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9406854.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-28
下一篇2023-04-28

发表评论

登录后才能评论

评论列表(0条)

    保存