近期列表Recents源码流程简单解析以及ActivityManager的简单使用:

本文详细解析了Android系统中近期列表RecentsActivity的源码流程,包括开机广播接收、RecentsActivity的生命周期及布局解析。同时介绍了ActivityManager的简单使用,如获取运行中的activity和服务,以及如何管理应用进程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android近期列表RecentsActivity的目录在/frameworks/base/packages/SystemUI/

frameworks的修改需要在fastboot模式下烧system.img文件。


首先,接受开机广播

 

处理它的Receiver类是BootReceiver。下面是Receiver的内容:


随后,在广播中开启了LoadAveragService服务。

SystemUiServier 服务也开启了

 

紧接着就是显示界面,主界面是RecentsActivity,首先onCreate(),onStart()

onCreate方法中发现布局文件是


接下来看一下布局文件


发现,基本都是自定义控件。

最下面的id = recents_no_apps,是列表中没有条目的时候才会显示。

查找会发现,这个id只有在RcentsPanelView中使用,接下来先看下:

定义一个View 


如果有apps的时候,就VISIBLE,否则就是INVISIABLE

上面noApps的值得来是根据mRecentTaskDescriptions,这是一个List


每一个app都保存成了一个TaskDescription。接下来看一下TaskDescription


它主要的字段有intent:用于跳转到应用,

    taskId,用于标识的id,比如删除,点击,跳转等使用。

  以及描述,包名等,icon等。。。

接着来查看一下当有信息的时候显示的布局,RecentsAcitvity的大布局是自定义的,实现类是RecentsPanelView


整个列表的大布局又放在了一个FrameLayout布局中,然后列表显示在一个自定义的布局中,实现类是RecentsVerticalScrollView

这个布局之后还有一个LinearLayout


简单解释几个参数

android:fitsSystemWindows="true"  字面意思就是使用系统窗口。总之是对布局的一种处理。

clipToPadding就是说控件的绘制区域是否在padding里面的,true的情况下如果你设置了padding那么绘制的区域就往里 缩,

clipChildren是指子控件是否超过padding区域,这两个属性默认是true的,所以在设置了padding情况下,默认滚动是在 padding内部的,要达到上面的效果主要把这两个属性设置了false那么这样子控件就能画到padding的区域了。

初始化列表,应该是在RecentsPanelView中完成的,

初始化简单到这里,接下来看看操作过程中的的流程。

首先,开机的时候,启动SystemUIServices,然后在onCreate中实例化了Recents

执行start(),然后执行closeRecents()方法。

开机后点击home键,会执行Recents类的preloadRecentTaskList方法。在里面启动了RecentsPreloadReceiver类。


销毁过程,首先是从内到外,SwipeHelper类中的onTouch方法对

MotionEvent.ACTION_CACEL进行匹配,方法实现如下:


前面绝大部分都是在得到能不能销毁的判断值dismissChild。如果可以销毁,就会执行

dismissChild(方法),如果滑动没有超过一定距离,就执行else中的内容。在上述方法中,基本实现的就是对动画的处理,如果显示动画效果,消除相应的view

紧接着就是RecentsVerticalScrollView类中的onChildDismissed()方法。


首先先看addToRecycledViews(v);从字面意思就是将需要消除的view添加到recycleview中。


一个简单的方法实现

然后就是mLinearLayout.removeView(v);在布局上移除相应的视图。

然后就是mCallback.handleSwipe(v);实际的实现在RecentsPanelView中。



首先获得TaskDescription,也就得到了某个条目的包括iddescription,等等信息。

然后每一个item是一个RecentTaskDescription对象,然后将这个对象移除了。

紧接着调用RecentTaskLoaderremove方法。


然后就是将存放的list集合的相应indexremove掉。


其实真正滑动销毁应用生效的一句话就是am.removeTask(ad.presistentTaskId,ActivityManager.REMOVE_TASK_KILL_PROCESS);

上面的内容是关键,根据存储的taskidkill掉相应的process


当长按home键直到显示RecentsActivity的过程中,流程log如下:


首先走的是Recetns类中的preloadRecentTaskList()方法。


在这个方法中,发送了广播RecentsPreloadReceiver

而且还调用了preloadFirstTask()方法来加载第一个Task

下图是RecentsPreloadReceiver的内容


当我们短按home键的时候,会先走if再走,再走else if,当长按home的时候,只走if,只有在home关闭的时候,才会走else if

说明,短按home键,也走了一遍查询的流程,然后瞬间又关闭掉了。

receiver中获得了RecentTaskLoader的实例后,调用了preloadRecentTaskList()方法,


在其中,用handler操纵了一个线程,线程中调用了loadTaskInBackground()方法,加载背景


下面就是loadTasksInBackground()方法


中间有个AsyncTask,用于加载初始化每个TaskdoInbackground中用for循环来遍历Task

For循环中有如下代码


每次加载一个task,都要调用createTaskDescription()方法


上面就是方法的内容。

接着会在BaseStatus类的toogleRecentActivity中调用Recents类的toogleRecents()方法。

 

然后就开始绘制界面,执行RecentsActivity类的oncreate方法

然后执行RecentVerticalScrollView类的setadapter,初始化列表。

然后执行onstart(),update(),.

当关闭这个界面的时候,会调用RecentPreloadReceiver中的RecentsActivity.CANCEL_PRELOAD_INTENT

然后RecentTasksLoader.getInstance(context).cancelPreloadingRecentTasksList();Cancel掉这个tasklist




然后调用RecentActivityonDestroy()


在方法体中进行了receiver的解绑

下面是onReceive中的操作,设置其show(false)


大致就是这样



ActivityManager

参考连接:http://androidbin.iteye.com/blog/1594908             http://www.apihome.cn/api/android/android.app

MainActivity

package com.example.activitymanagerdemo;

import java.util.List;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	private Button button1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		button1 = (Button) findViewById(R.id.btn1);
		button1.setOnClickListener(this);

	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn1:
			Intent intent = new Intent(this, TestActivity.class);
			startActivity(intent);
			// finish();
			break;

		default:
			break;
		}
	}

}

TestActivity

package com.example.activitymanagerdemo;

import java.util.Arrays;
import java.util.List;

import android.R.integer;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class TestActivity extends Activity {

	public ActivityManager am;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);

		Button button = (Button) findViewById(R.id.btn1);
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				getOrigRunningList();
			}
		});

	}

	/**
	 * 需要添加权限android.permission.GET_TASKS
	 * 界面是从MainActivity跳转到当前的TestAtivity的。
	 * 如果,没有finish掉MainAcitity,获得的getClassName()和cn.getShortClassName();获得的是关于MainActivity的
	 * 如果跳转的时候finish()掉,说明TestActtivity底部就没有其他的Activity了,得到的就是关于TestActivity的结果
	 */
	private void getRunningTaskName() {
		// 获取顶部的activity
		ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
		// 获取底部的activity。
		ComponentName cn1 = am.getRunningTasks(1).get(0).baseActivity;
		// 将maxTasks设置成2,就是最多获得两个应用的task。
		// get(x)中的值x,是获得应用的角标,最上面一层是0,依次往下是1、2、3...
		// get(1),就是获得第二层的应用,比如说我现在正在看短信,忽然电话来了,call应用覆盖了短信,call在上面,此时call应用就是get(0),
		// 短信mms就是get(1)。然后在决定获得短信的base还是top
		ComponentName cn3 = am.getRunningTasks(2).get(1).baseActivity;
		ComponentName cn4 = am.getRunningTasks(2).get(1).topActivity;
		// 更具ComponentName获得需要的activity的名字
		String topAtyName = cn.getClassName();
		// 获得应用的包名
		String topPkgName = cn.getPackageName();
		// 获得“.MainActivity”形式的结果
		String topScName = cn.getShortClassName();
		System.out.println("topAtyName--->" + topAtyName);
		System.out.println("topPkgName--->" + topPkgName);
		System.out.println("topScName--->" + topScName);
	}

	/**
	 * 获取表示task的id,进行销毁操作
	 */
	private void getRunningtaskList() {
		List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasks(1,
				ActivityManager.RECENT_IGNORE_UNAVAILABLE);
		ActivityManager.RecentTaskInfo rtInfo = recentTasks.get(0);
		int persistentId = rtInfo.persistentId;
		int id = rtInfo.id;
		System.out.println("persistentId--->" + persistentId);
		System.out.println("id--->" + id);
		// 可以根据唯一的标识task id进行销毁应用
		// am.removeTask(persistentId,
		// ActivityManager.REMOVE_TASK_KILL_PROCESS);
	}

	/**
	 * 获得系统正在运行的进程
	 */
	private void getRuningProcessList() {
		List<ActivityManager.RunningAppProcessInfo> appList1 = am
				.getRunningAppProcesses();
		for (RunningAppProcessInfo running : appList1) {
			System.out.println("process--->" + running.processName);
			System.out.println("pid--->" + running.pid);
			// 所有已加载到进程中的包。大部分只有一个包名,和processName一致,个别的有两个包名
			System.out
					.println("pkgList--->" + Arrays.toString(running.pkgList));
			System.out.println("uid--->" + running.uid);
		}
	}

	/**
	 * 获得系统正在运行的service
	 */
	private void getRunningServiceList() {
		List<ActivityManager.RunningServiceInfo> serviceList = am
				.getRunningServices(1000);
		for (RunningServiceInfo running : serviceList) {
			System.out.println("--->" + running.service.getClassName());
			System.out.println("--->" + running.service.getPackageName());
		}
	}

	private void getOrigRunningList() {
		List<ActivityManager.RecentTaskInfo> origList = am.getRecentTasks(100,
				1);
		for (RecentTaskInfo running : origList) {
			System.out.println("origActivityName--->>"
					+ running.origActivity.getClassName());
			System.out.println("origPkgName--->>"
					+ running.origActivity.getPackageName());
		}
	}
}




http://www.apihome.cn/api/android/android.app

ActivityManager--获得正在运行的activitiy与service   http://androidbin.iteye.com/blog/1594908

Android中获取正在运行的应用程序--ActivityManager.RunningAppProcessInfo类详解  http://blog.youkuaiyun.com/qinjuning/article/details/7009824

Android中获取系统内存信息以及进程信息--ActivityManager的使用  http://blog.youkuaiyun.com/qinjuning/article/details/6978560







<think>好的,我现在需要处理用户关于安卓13版本代码的请求。首先,用户之前询问的是如何在小米手机上使用bash脚本切换到2G网络,现在转向了安卓13的代码介绍。这可能意味着用户对安卓系统底层有持续的兴趣,或者他们正在开发相关应用,需要深入了解系统架构。 首先,我要明确用户的需求。他们可能想了解安卓13的新特性、源代码结构,或者如何获取和编译代码。考虑到用户之前涉及root权限和脚本操作,他们可能有开发或定制系统的需求,比如ROM开发或系统级应用开发。 接下来,我需要组织回答的结构。用户可能希望一个清晰的步骤指南,包括代码获取、关键模块介绍和新特性。同时,要确保使用中文,并遵循之前的格式要求,比如行内公式用$...$,独立公式用$$...$$,虽然这里可能用不上太多数学公式,但要注意LaTeX的正确使用。 然后,我需要验证安卓13的代码获取方式。AOSP官网是主要来源,repo工具的使用是关键步骤。要详细说明初始化仓库和分支切换的命令,确保用户能正确操作。同时,要提醒网络和存储空间的问题,因为下载AOSP代码需要大量带宽和磁盘空间。 关于代码结构,需要列出核心目录并解释每个部分的作用,比如内核、系统服务、硬件抽象层等。用户可能需要这些信息来定位他们感兴趣的模块,比如修改系统服务或硬件驱动。 新特性部分,安卓13的隐私、UI改进和大屏优化是重点。要简明扼要地列出每个特性,并举例说明相关的代码位置,帮助用户快速找到相关模块。比如,照片选择器对应Intent的处理,通知权限在PackageManager的修改。 注意事项部分需要强调法律风险,特别是GMS的许可问题,避免用户无意中违反谷歌的政策。此外,编译环境和设备兼容性也是常见问题,提前告知可以减少用户的试错成本。 最后,用户可能的问题包括如何调试、定制ROM或解决兼容性问题。在回答中虽然没有直接提到,但通过提供代码结构和模块信息,用户可能自行进一步探索。如果有后续问题,需要准备好深入解答具体的技术细节。 需要确保回答符合格式要求,使用适当的代码块,避免使用Markdown,但根据用户之前的回复,似乎允许代码块。同时,检查LaTeX是否正确,尽管当前内容可能不需要太多公式。最后,保持回答结构清晰,逐步引导用户理解安卓13的代码结构和获取方式,满足他们的开发或学习需求。</think>以下是关于**Android 13(API 33,代号 Tiramisu)**系统代码的核心信息解析,从开发者角度梳理关键内容: --- ### **1. 代码获取与编译** #### **1.1 官方源码获取** Android 13 代码托管在 [AOSP(Android Open Source Project)](https://source.android.com/): ```bash # 初始化仓库(需安装repo工具) repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_rXX # 同步代码(约150GB) repo sync -j$(nproc) ``` > **注**:`_rXX`为具体版本号(如 `android-13.0.0_r41`),需查阅[版本标记列表](https://source.android.com/docs/setup/start/build-numbers#source-code-tags-and-builds)。 #### **1.2 关键代码分支** - **内核层**:`kernel/common`(Linux Kernel 5.15+) - **系统服务**:`frameworks/base` - **硬件抽象层(HAL)**:`hardware/interfaces` - **应用框架**:`packages/apps` --- ### **2. 代码架构核心模块** #### **2.1 分层结构** | 层级 | 代码路径 | 功能描述 | |-------------|---------------------------|-----------------------------------| | **应用层** | `packages/apps` | 预装系统应用(设置、电话等) | | **框架层** | `frameworks/base` | ActivityManager、WindowManager | | **Native层**| `system/core` | Binder、Zygote进程管理 | | **内核层** | `kernel/` | 驱动、电源管理、进程调度 | #### **2.2 关键服务代码** - **网络管理**:`frameworks/base/services/core/java/com/android/server/connectivity/` - **权限控制**:`frameworks/base/services/core/java/com/android/server/pm/` - **传感器服务**:`frameworks/base/services/core/java/com/android/server/sensors/` --- ### **3. Android 13 新特性代码实现** #### **3.1 隐私增强** - **照片选择器** 代码路径:`frameworks/base/core/java/android/content/Intent.java` 新增 `ACTION_GET_CONTENT` 的 `TYPE_IMAGES` 限制模式。 - **通知权限** 代码修改:`frameworks/base/services/core/java/com/android/server/pm/permission/` 添加 `POST_NOTIFICATIONS` 运行时权限校验。 #### **3.2 图形与UI** - **预测性返回手势** 代码路径:`frameworks/base/core/java/android/view/KeyEvent.java` 新增 `PredictionBackEvent` 回调接口。 - **动态色彩主题** 资源生成逻辑:`frameworks/base/packages/SystemUI/src/com/android/systemui/monet/` #### **3.3 大屏优化** - **任务栏多任务** 代码修改:`frameworks/base/packages/SystemUI/src/com/android/systemui/recents/` --- ### **4. 开发者调试技巧** #### **4.1 快速查看API变更** ```bash # 对比Android 12与13的API差异 ./prebuilts/check-api/checkapi.py --current out/target/common/obj/PACKAGING/android_public_api.txt --previous aosp-android-12.0.0_r32.txt ``` #### **4.2 模块化编译** ```bash # 单独编译Settings应用 source build/envsetup.sh lunch aosp_arm-eng mmm packages/apps/Settings/ ``` --- ### **注意事项** 1. **法律限制** AOSP代码可自由修改,但**GMS(Google Mobile Services)**需谷歌授权。 2. **硬件兼容性** 厂商定制代码(如小米MIUI)通常不公开,需通过逆向分析或官方开发者文档获取。 3. **编译环境** 推荐使用Ubuntu 20.04+,分配至少16核CPU/64GB RAM/500GB SSD。 --- 如需深入特定模块(如Binder通信机制或HAL层实现),可提供具体方向进一步解析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值