首页 > 其他分享 >Activity管理

Activity管理

时间:2023-03-22 22:35:09浏览次数:36  
标签:调用 管理 启动 应用程序 Intent Activity AMS

AMS启动过程

在Android应用启动流程中,AMS( Activity Manager Service )的启动是非常关键的。以下是AMS的启动过程:

1.进程启动

当我们启动一个应用时,系统会挂起Zygote进程。然后,Zygote生成新的应用进程,乘坐第一辆列车到达了Android的世界。这样一来,应用就有了属于自己的执行环境。

2.初始化AMS

  应用进程执行后,它会初始化AMS对象,其实AMS就是整个Android应用启动的大管家,负责管理所有Activity、Service以及Task栈等。

3.启动Activity

  用户点击应用图标,系统判断该Activity所在进程是否启动,如果未启动,则调用Zygote生成对应的新进程,生成进程后再创建对应的Activity对象,并展示到界面上(不包括横竖屏切换和窗口切换)。

4.与AMS交互实现Activity启动

  •   首先,ActivityManagerNative.getDefault() 获取跨进程调用的接口对象singleton
  •   然后,调用方法startActivityAsUser(userId, ..., args) 向AMS发送请求,申请启动一个Activity
  •   AMS收到请求后,判断 Activity 所在进程是否存在,若不存在则创建。创建完成后,将ActivityRecord加入ActivityStacktask中。

5.Zygote启动Application

  如果说AMS是Android应用启动的大管家,那么Zygote就是应用启动的魔法师。当Zygote进程创建好了Activity进程,并已经给AMS抛出了Activity生命周期的事件之后,AMSi即可调用Zygote方法去“打开”这个应用程序。Zygote取得类路径和参数信息,并解析出主函数所对应的类名和方法名,最终通过反射技术,加载指定文件并运行里面的静态main()方法。

AMS重要数据结构解析

  1. ProcessRecord:进程记录是AMS管理应用程序的最底层数据结构之一,它维护了一个应用程序的所有信息,包括包名、UID、进程名、用户ID等。每个进程记录都与一个ApplicationRecord关联,表示该进程所对应的应用程序。

  2. ActivityRecord:指Activity在AMS内部的表示,其本质是一个封装了Activity对象和相关状态信息的类。AMS通过ActivityRecord来管理Activity组件的创建、启动、停止等操作。

  3. TaskRecord:指任务栈记录,又称作任务记录。Android应用程序通常由多个Activity组成,并按照一定的调用顺序形成不同的任务栈。每个TaskRecord记录了一个任务栈中所有Activity的顺序以及运行状态。

  4. IntentRecord:指Intent请求记录,也称Activity请求记录,AMS通过此数据结构来存储Activity启动请求,例如Intent的Action、Category、Data等信息,在后续启动过程中进行匹配以确定启动哪个Activity。

在Android实际应用开发中,开发者可以利用AMS提供的API来实现各种复杂的逻辑。例如:

  1. 跨进程通信:借助Binder机制和AMS的辅助,在不同进程之间传递消息或执行远程方法调用,实现跨应用或服务端/客户端的各种功能。

  2. 启动模式管理:通过设置不同的Activity启动模式,灵活管理Activity的启动行为,例如SingleTop模式避免Activity重复创建,FlagActivity模式实现不同自定义标记的特殊行为等。

  • standard :系统的默认模式,一次跳转即会生成一个新的实例。假设有一个activity命名为MainActivity,执行语句:
    startActivity(new Intent(MainActivity.this, MainActivity.class))后,MainActivity将跳转到另外一个MainActivity,也就是现在的Task栈里面有MainActivity的两个实例。 按返回键后你会发现仍然是在MainActivity(第一个)里面。 显示不同列表信息;

  • singleTopsingleTopstandard 模式比较类似。如果已经有一个实例位于Activity栈的顶部时,就不产生新的实例,而只是调用Activity中的newInstance()方法。如果不位于栈顶,会产生一个新的实例。例:当MainActivitysingleTop 模式时,执行跳转后栈里面依旧只有一个实例,如果现在按返回键程序将直接退出。 通知或即时响应界面;

    Activity类中,如果开发人员需要为活动添加一些输入参数,则可以使用静态的newInstance()方法来创建一个新的Activity实例。 newInstance()方法必须在实例化的过程中手动设置数据传递,这样可以避免外部代码直接访问类的成员变量,在处理屏幕旋转和内存重新启动时更加方便。

    例如,对于一个简单的活动,可以定义一个静态的`newInstance()`方法,该方法将通过一个Bundle将整数保存到Activity的arguments字段中。然后,在Activity的onCreate方法中,可以调用getArguments()以获取该数字。
    
    ```java
    public class MyActivity extends Activity {
        private static final String ARG_MY_INT = "my_int";
    
        private int myInt;
    
        public static MyActivity newInstance(int myInt) {
            Bundle args = new Bundle();
            args.putInt(ARG_MY_INT, myInt);
            MyActivity f1 = new MyActivity();
            f1.setArguments(args);
            return f1;
        }
    
        @Override public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (getArguments() != null) {
                myInt = getArguments().getInt(ARG_MY_INT);
            }
        }
    }
    
    ```
    	
    在这个例子中,使用者可以像这样来启动Activity:
    
    ```java
    MyActivity.newInstance(42);
    ```
    
    • singleTask singleTask模式和后面的singleInstance模式都是只创建一个实例的。在这种模式下,无论跳转的对象是不是位于栈顶的activity,程序都不会生成一个新的实例 (当然前提是栈里面已经有这个实例)。这种模式相当有用,在以后的多activity开发中,经常会因为跳转的关系导致同个页面生成多个实例,这个在用户体验上始终有点不好,而 如果你将对应的activity声明为 singleTask 模式,这种问题将不复存在。 比如首页;

    • singleInstance: 设置为 singleInstance 模式的 activity 将独占一个task(感觉task可以理解为进程),没有就新建然后放到独立task里。比如系统默认电话界面。

  1. 进程垃圾清理:合理使用AMS提供的Process.killProcess等API,及时关闭无用的进程,释放存储空间和CPU资源。

ActivityStack 不是一个具体的物理存在,而是Android系统在内存中维护的一个数据结构。它表示所有已启动的 Activity 的集合以及它们在屏幕上的顺序。

可以通过 ActivityThread 类的 getApplication() & getActivities() 方法来获取应用程序中所有Activity实例相关的信息。其中,getActivities() 方法会返回一个 ArrayMap ,Key 值为 IBinder 对象(通过此对象可以与每个 Activity 交互),Value 值为 WeakReference 对象(弱引用指向了相应的 Activity 实例)。

lntent的Flag与taskAffinity

Activity启动流程大致分为以下几个步骤:

  1. 当需要启动一个新的Activity时,会向AMS发送启动请求。

  2. AMS会根据该请求创建一个WaittingRecord并将其添加到待处理队列中。

  3. AMS会检查当前进程的可用性,如果存在一个运行在该进程中的Activity,则该Activity所在的进程会直接被使用;否则,就需要启动一个新的进程来承载即将启动的Activity。

  4. 如果需要启动一个新进程,则AMS会利用Zygote fork出一个新进程,并启动该进程的主线程。

  5. 在新的进程中,会创建一个Application Object和ActivityThread对象,并把ActivityThread添加到主线程的消息循环中。

  6. ActivityThread会依次完成Looper、AMS Binding、Handler回调等步骤。

  7. 通过AMS获取ActivityInfo和TaskAffinity,然后再根据Intent中相关配置启动Activity,并使用Token进一步关联Activity和进程之间的交互。

至于TaskAffinityFlag,其中TaskAffinity是任务归属的属性,在Android系统中会以字符串形式对Activity进行打标签。每一个Activity都绑定着一个Task,标识成为“任务”(Task)的名字就是这个Activity的TaskAffinity属性值, 每个Task可以有多个Activity。而Flag是与Intent相关的,用于定义Activity的启动模式和行为,比如FLAG_ACTIVITY_NEW_TASK会在启动Activity时创建一个新的任务栈。

TaskAffinity指定了应用程序组件要加入哪个任务。

在 AndroidManifest 文件中,可以为应用程序或 Activity 指定 affinity 属性。如果不使用 affinity 属性,则默认情况下 Activity 的名称成为任务 affinity。TaskAffinity 可以在代码中被动态修改。 要动态更改 TaskAffinity,请在执行 startActivityForResult() startActivity() 时清除 Intent taskAffinity 属性,如以下示例所示:

Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
	
// Dynamic modify task affinity
if (newCondition) {
    intent.setTaskAffinity("com.example.newtaskaffinity");
} else {
    intent.setTaskAffinity("com.example.othertaskaffinity");
}
startActivity(intent);

FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TOP 标志确保启动一个新的活动且使其成为栈顶,以便直接与其他具有相同 TaskAffinity 的 Activities 进行交互。在上述示例中,通过根据特定条件来动态地更改 setTaskAffinity 调用的参数可以改变任务的规则。

在实际开发中,我们可以利用Flag参数控制Activity的启动方式,很多场景下需要Activity跨进程启动,这时可以使用FLAG_ACTIVITY_NEW_TASK。另外,我们也可以通过设置taskAffinity改变Activity所在的任务栈,比如通过设置taskAffinity="com.example.myApp.task1"将应用程序中的某些Activity归属到同一个任务栈中,从而方便管理。

activity启动流程

在理解Activity的启动流程之前,我们需要先了解以下几个概念:

  • Context:表示Android应用程序环境,比如Activity、Service等。
  • Application:全局应用程序上下文,一个应用程序只有一个Application实例。
  • ActivityManagerService(AMS):负责协调应用程序中所有组件的运行情况的系统服务。
  1. 启动Activity

Activity的启动过程通常是通过Context.startActivity()方法触发的。当一个Activity要启动时,就会发送一个启动请求给AMS。

  1. 请求验证和分配task

AMS接收到请求后,首先会验证并分配一个Task给新的Activity实例,这个过程会根据Intent中带的标志进行判断,一般情况下系统会为新的Activity实例创建一个新的Task,并将它放入最近使用的任务列表的顶端;而如果同时在Intent中设置了FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP标志,那么AMS就会找到与该Activity具有相同taskAffinity属性的Activity所在的任务栈。

  1. 发送生命周期回调

AMS会调用Activity的onCreate()、onStart()和onResume()方法,这些方法会导致Activity进入运行状态。然后AMS把Activity添加到栈顶并更新屏幕显示。

  1. AMS销毁不活跃的Activity

当新的Activity启动后,AMS会对任务栈中其它Activity进行处理。首先回调onPause,等到返回屏幕再去调度其他任务栈。如果他影藏了当前Activity,我们的这个Activity也会被调整到后台并停止响应,Activity渲染的数据会被保存在当前Activity里面。当用户再次打开这个Activity时从数据中读取数据,在屏幕,AMS仅仅涉及到该Activity是否可见,如果不可见就会立即调用onStop()。在后台运行的非常久远的任务栈都可能被AMS kill、清除的。

  1. 销毁Activity

一般来说,Activity的销毁过程如下:
onPause()->onStop()->onDestroy()。

关于Hook实现启动未注册Activity

假设我们有一个名为TargetActivity的Activity,并希望在我们的应用程序中动态启动它,但是没有对其进行注册。我们可以使用Hook来实现这一点。具体步骤如下:

1.创建一个代理Activity,例如ProxyActivity,并将其添加到清单文件中。 在此步骤中,请注意将标签设置为“主要类别”,以便让系统认为它是应用程序的入口点。 以下是示例代码:

<activity android:name=".ProxyActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="app" />
    </intent-filter>
</activity>

2.在ProxyActivity中,使用反射获取ActivityThread对象,并通过它获取IActivityManager对象。

Class activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
Object activityThread = currentActivityThreadMethod.invoke(null);
Field iActivityManagerField = activityThreadClass.getDeclaredField("mInstrumentation");
iActivityManagerField.setAccessible(true);
Object iActivityManager = iActivityManagerField.get(activityThread);

3.创建一个假的Intent,将目标Activity的名称作为参数传递。

Intent intent = new Intent();
intent.setComponent(new ComponentName(getPackageName(), "com.example.TargetActivity"));

4.调用IActivityManager对象的startActivity方法,以启动指定的Activity。 在调用该方法之前,我们需要创建一个回调PendingIntent,并将其作为“intentSender”参数传递给该方法。

// Create a Pending Intent for the callback.
Intent callbackIntent = new Intent(this, ProxyActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, callbackIntent, PendingIntent.FLAG_ONE_SHOT);

// Start the Target Activity using IActivityManager.
Method startActivityMethod = iActivityManager.getClass().getDeclaredMethod("startActivity", IApplicationThread.class, String.class, Intent.class, String.class, IBinder.class, String.class, int.class, int.class, ProfilerInfo.class, Bundle.class);
startActivityMethod.setAccessible(true);
startActivityMethod.invoke(iActivityManager, null, null, targetIntent, null, null, null, 0, 0, null, null);

在这个示例中,我们假装从ProxyActivity启动了TargetActivity,而不是直接从应用程序启动。 这允许我们绕过您必须对所有要启动的Activity进行注册的限制。

Activity的生命周期可分为以下四个状态:

  1. Running - Activity位于栈顶,正在与用户进行交互。
  2. Paused - 当前Activity失去了输入焦点,不再接收用户输入,但仍可显示在屏幕上。或者被另一个 Activity 部分遮挡而失去焦点时被调用。
  3. Stopped - Activity不再可见,已经被另一个Activity完全覆盖了。
  4. Destroyed - Activity已经被销毁,内存资源已释放。

Activity生命周期方法

以下是Activity生命周期中的主要方法:

  1. onCreate() - 在该方法中完成必要的初始化操作,如加载布局、绑定事件等。
  2. onStart() - 在该方法中进行Activity的启动操作,如请求网络、打开数据库等。
  3. onResume() - 在该方法中完成Activity的恢复操作,如恢复播放音乐、重新开始动画等。
  4. onPause() - 在该方法中处理失去用户焦点的情况,如保存当前编辑的内容、暂停视频观看等。
  5. onStop() - 在该方法中完成Activity的停止操作,如释放资源,取消注册广播等。
  6. onDestroy() - 在该方法中释放系统资源、取消注册监听器等。

Android中的Activity 生命周期回调顺序

当用户打开一个 Activity 时,Activity 进入 Created 状态并按照以下顺序调用:

  1. onCreate() - 在活动第一次创建时被调用。
  2. onStart() - 当活动对用户可见时被调用。在这个阶段,它已经获得了焦点。
  3. onResume() - 当活动与用户开始交互时被调用。

如果在此期间用户暂停了 Activity,则该 Activity 将进入 Paused 状态并依次调用:

  1. onPause() - 当前活动对用户不再可见时调用。当他只是部分可见或透明时,也可能发生这种情况。在执行下一个活动或返回到主屏幕时,系统将继续调用“ onStop()”或onRestart()方法。
  2. onStop() - 在 Activity 完全被另一个 Activity 覆盖或者销毁时被调用。在在手机上或平板电脑等小型设备上可以忽略该方法。
  3. onDestroy() - 活动从堆栈中弹出时调用。

如果用户想要恢复之前的 Activity,则将按照以下顺序调用它们:

  1. onRestart() - Called after your activity has been stopped, prior to it being started again. 目的是当活动正在重新启动时来重新初始化某些变量。
  2. onStart() - 与刚刚创建 Activity 时调用的方式相同。
  3. onResume() - 与刚刚创建 Activity 时调用的方式相同。

前台activity和后台activity

  • 当前台 Activity 不再可见(如因为新 Activity 启动),系统便会调用 onPause(), 确保 Activity 的数据已经保存。

  • 如果用户返回当前 Activity,系统便会调用 onResume(), 允许它重新开始。

  • 处理周期性任务、定时器、更新 UI 或执行其他操作,请使用 onResume()onPause() 方法。

  • 对于较大的内存块,请使用 onStop() 方法保存更改。如果您发现需要立即释放资源且没有延迟容忍的时间,请使用 onPause() 代替。

  • 如果 Activity 刚退出前台并即将进入后台,可以利用 onSaveInstanceState() 方法在其开始 onSaveInstanceState() 时进行某些处理,持久化 Activity 的图像等重要数据。.onOptionsItemSelected() 是另一个选择。

activity中adj

在Android中,每个应用程序的进程都具有一个adj(oom_adj值),该值决定了系统如何对该应用程序进行内存管理。 adj值越高,表明应用程序是最有可能被终止的。Activity中包含的组件和服务也会继承相同的adj值。

默认情况下,所有应用程序都分配了较低的adj值,这意味着它们占用的内存不够时最有可能被kill。为了防止这种情况发生,并保持应用程序在前台运行,可以调整或设置其adj值。

要设置Activity的ad,则需要使用android:process属性以及android:priority属性。具体如下:

<application android:process=":my_process">
    <activity android:name=".MyActivity"
              android:priority="1000">
    </activity>
</application>

上述代码将创建一个新进程(my_process),并将Activity的优先级设置为1000。请注意,使用此选项应该非常小心,因为如果您设置的优先级太高,可能会影响系统的整体性能。

另外,在API 21及更高版本中,您还可以使用TaskDescription类的setTaskDescription方法来设置应用程序堆栈的描述。这反过来会影响系统如何处理应用程序的内存管理。例如:

ActivityManager.TaskDescription description = new ActivityManager.TaskDescription("Label",
        BitmapFactory.decodeResource(getResources(), R.drawable.icon),
        ContextCompat.getColor(this, R.color.colorPrimary));
setTaskDescription(description);

通过使用setTaskDescription()方法,您可以更改堆栈的标签、图标和颜色,使其在Recents列表中更加易于区分和查看,并帮助您控制应用程序的adj值。

标签:调用,管理,启动,应用程序,Intent,Activity,AMS
From: https://www.cnblogs.com/fuunnyy/p/17245733.html

相关文章

  • 使用OpenSearch 构建日志监控与管理平台
    基于Windows平台环境搭建:步骤一:在OpenSearch官方网站下载Windows平台最新安装包,写作时当前最新版本是2.6.0,也可直接通过以下链接直接下载:OpenSearch下载: https://ar......
  • Vue3学习笔记 —— 状态管理、Vuex、Pinia (未完结)
    优秀文章分享:vue中使用vuex(超详细)-掘金(juejin.cn)一、状态管理1.1、什么是状态管理?理论上来说,每一个Vue组件实例都已经在“管理”它自己的响应式状态了。我们以......
  • 智能控制 | AIRIOT智慧楼宇管理解决方案
    许多行业客户在智慧楼宇的建设中主要面临运营管理低效,楼宇内部各个系统相互独立,不仅管理操作复杂,而且各系统间的数据无法分享,无法支撑大数据分析。此外,由于楼宇管理系统的低......
  • Huawei_VRP_用户管理与AAA
    目录引子AAA华为设备登录管理小案例新同事CE12800引子和同学一块做项目,让同事配置一个AAA认证,结果好长时间没搞好,后来一看配置的命令如上图所示,同学在那里用console线在......
  • 基本分页存储管理的概念
    基本分页存储管理的概念1、什么是分页存储2、重要的数据结构页表问题一:每个页表项占多少字节?问题二:如何实现地址的转换?1)如何确定一个逻辑地址对应的页号、......
  • 安全管理要坚持的五项原则
    安全管理是企业管理的重要组成部分,是对生产过程中一切人、物、环境状态的动态管理与控制,是企业发展的生命线。安全管理主要包括企业对安全生产的规划、实施、指导和检查,是保......
  • 一文读懂ISO27001信息安全管理体系
    ISO信息安全管理体系1、ISO信息安全管理体系是组织在整体或特定范围内建立信息安全方针和目标,以及完成这些目标所用方法的体系。2、信息安全管理体系认证ISO信息安全管理体......
  • 在 windows 上使用 pm2 管理 syncthing 存在弹窗的问题
    方向1使用start的/b参数来运行,它可以实现类似linuxnohup的后台效果,但如果退出父进程,后台也结束了.方向2使用winsw这些工具,把程序注册为服务.由于不......
  • 网络基础设施管理的未来
     01什么是网络基础设施?Cisco的定义:Networkinfrastructurereferstothehardwareandsoftwarethatenablenetworkconnectivityandcommunicationbetweenusers,de......
  • 「ACM 算法实践」[解题报告]时间管理大师
    分析一开始想着应该要分情况讨论,如果每台电脑的耗电量都小于\(e\),那么可以知道小Q是可以一直学习下去的,如果存在电脑的耗电量大于等于\(e\),贪心的想法是将每台电脑......