Android Framework AMS(07)service组件启动分析-1(APP到AMS流程解读)

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:本章节主要解读应用层service组件启动的2种方式startService和bindService,以及从APP层到AMS调用之间的打通。关注思维导图中左侧部分即可。

有了前面startActivity流程分析的基础,接下来我们来分析service组件启动的流程。

在Android中,startService和bindService是两种不同的服务(Service)启动方式,它们在应用中的作用和使用场景有所不同。下面我将通过两个demo来说明它们之间的区别。

1 startService VS bindService

1.1 startService解读及应用

startService用于启动一个服务,该服务会在后台运行,即使启动它的组件已经不存在,服务也会继续运行。这种服务适合执行一些不需要与用户交互的任务,比如下载文件、播放音乐等。

假设我们有一个音乐播放器应用,用户可以在应用界面选择播放音乐,然后即使用户切换到其他应用或者锁屏,音乐仍然可以继续播放。

// MusicService.java
public class MusicService extends Service {private MediaPlayer mediaPlayer;@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {mediaPlayer = MediaPlayer.create(this, R.raw.music_file);mediaPlayer.start();return START_STICKY;}@Overridepublic void onDestroy() {super.onDestroy();if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();}}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}
}// MainActivity.java
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button playButton = findViewById(R.id.play_button);playButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, MusicService.class);startService(intent);}});}
}

在这个案例中,我们通过startService启动了MusicService服务,即使用户离开了MainActivity,音乐仍然可以继续播放。

1.2 bindService解读及应用

bindService用于绑定一个服务,这样可以允许组件与服务进行交互,比如请求服务执行某些操作或者获取服务提供的数据。这种服务适合需要与用户交互或者需要组件与服务进行通信的场景。

假设我们有一个应用,需要从网络加载数据,并且需要在多个Activity之间共享这些数据。

// DataLoadingService.java
public class DataLoadingService extends Service {private List<String> data;private final IBinder binder = new LocalBinder();public class LocalBinder extends Binder {DataLoadingService getService() {return DataLoadingService.this;}}public List<String> getData() {return data;}@Overridepublic IBinder onBind(Intent intent) {return binder;}@Overridepublic boolean onUnbind(Intent intent) {// 可以在这里处理解绑逻辑return super.onUnbind(intent);}
}// MainActivity.java
public class MainActivity extends AppCompatActivity {private DataLoadingService dataLoadingService;private boolean isBound = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this, DataLoadingService.class);bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);}private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {DataLoadingService.LocalBinder binder = (DataLoadingService.LocalBinder) service;dataLoadingService = binder.getService();isBound = true;// 可以在这里请求服务加载数据}@Overridepublic void onServiceDisconnected(ComponentName arg0) {isBound = false;}};@Overrideprotected void onDestroy() {super.onDestroy();if (isBound) {unbindService(serviceConnection);isBound = false;}}
}

在这个案例中,我们通过bindService绑定了DataLoadingService服务,这样MainActivity就可以与服务进行交互,比如请求服务加载数据。最后总结下:

  • startService适合执行不需要与用户交互的后台任务,服务一旦启动,即使启动它的组件不存在,服务也会继续运行。
  • bindService适合需要与用户交互或者需要组件与服务进行通信的场景,服务的生命周期与绑定它的组件相关联。

接下来我们开始以activity场景中的startService和bindService为入口,开始分析。

2 从activity场景到AMS调用的流程

2.1 从activity.startService到AMS.startService

activity.startService方法是从Context中的startService开始调用的,接口代码实现如下:

//Context 
public abstract ComponentName startService(Intent service);

其真正的实现是在ContextImpl中,代码实现如下:

//ContextImpl//关键流程:step1@Overridepublic ComponentName startService(Intent service) {warnIfCallingFromSystemProcess();return startServiceCommon(service, mUser);}//关键流程:step2private ComponentName startServiceCommon(Intent service, UserHandle user) {try {validateServiceIntent(service);service.prepareToLeaveProcess();//关键方法:调用AMS的startService方法ComponentName cn = ActivityManagerNative.getDefault().startService(mMainThread.getApplicationThread(), service,service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());//...return cn;} catch (RemoteException e) {return null;}}

这里直接调用到ActivityManagerNative.getDefault().startService,实际上最终就是调用到AMS的startService方法中。这一部分参考binder系列文章即可,有了或者基础分析起来就较为简单了。系列文章链接为:专题分纲目录 android 系统核心机制 binder,尤其是这2篇偏实操的:

android 系统核心机制binder(11)binder java层 TestServer分析

android 系统核心机制binder(12)binder java层 TestClient  分析

2.2 从activity.bindService到AMS.bindService

activity.bindService方法是从Context中的bindService开始调用的,接口代码实现如下:

//Context   public abstract boolean bindService(Intent service, @NonNull ServiceConnection conn,@BindServiceFlags int flags);

其真正的实现是在ContextImpl中,代码实现如下:

//ContextImpl//关键流程:step1@Overridepublic boolean bindService(Intent service, ServiceConnection conn,int flags) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, flags, Process.myUserHandle());}//关键流程:step2private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,UserHandle user) {IServiceConnection sd;//...if (mPackageInfo != null) {sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),mMainThread.getHandler(), flags);} else {throw new RuntimeException("Not supported in system context");}validateServiceIntent(service);try {IBinder token = getActivityToken();if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null&& mPackageInfo.getApplicationInfo().targetSdkVersion< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {flags |= BIND_WAIVE_PRIORITY;}service.prepareToLeaveProcess();//关键方法:调用AMS的bindService方法int res = ActivityManagerNative.getDefault().bindService(mMainThread.getApplicationThread(), getActivityToken(),service, service.resolveTypeIfNeeded(getContentResolver()),sd, flags, user.getIdentifier());if (res < 0) {throw new SecurityException("Not allowed to bind to service " + service);}return res != 0;} catch (RemoteException e) {return false;}

这里直接调用到ActivityManagerNative.getDefault().bindService,实际上最终就是调用到AMS的bindService方法中。其中过程参考2.1节即可。

有了这些基础,接下来的2个章节我们开始分析从AMS.startService和AMS.bindService到最终回调的流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/56525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

microsoft edge浏览器卡死问题

win11经常遇到microsoft edge浏览器卡死的情况&#xff0c;有时候是一会没用浏览器就全部卡死&#xff0c;有时候是锁屏或者电脑休眠浏览器就不能用&#xff0c;找了很多的办法都没好使&#xff0c;用以下方法好使了&#xff1a; edge浏览器中打开 edge://settings/system 把 …

Cornerstone3D Tools对影像进行交互(中篇)-注释类工具使用

&#x1f3c4;‍♀️ 前言 这里是关于Cornerstone3D Tools对影像进行交互&#xff08;中篇 &#xff09;- 注释类工具的使用介绍。在 Cornerstone3D Tools对影像进行交互(上篇)-基础交互工具及同步器 一文中主要介绍了一下基础交互类工具的使用&#xff0c;感兴趣的小伙伴可以…

【优先算法】--双指针1

“一念既出&#xff0c;万山无阻。”加油陌生人&#xff01; 目录 1.双指针--移动零 2.双指针-复写零 ok&#xff0c;首先在学习之前&#xff0c;为了方便大家后面的学习&#xff0c;我们这里需要补充一个知识点&#xff0c;我这里所谓的指针&#xff0c;不是之前学习的带有…

Linux 外设驱动 应用 2 KEY 按键实验

2 按键 2.1 按键介绍 按键是指轻触式按键开关&#xff0c;也称之为轻触开关。按键开关是一种电子开关&#xff0c;属于电子元器件类&#xff0c;最早出现在日本&#xff0c;称之为&#xff1a;敏感型开关&#xff0c;使用时以满足操作力的条件向开关操作方向施压开关功能闭合…

【笔记】Day2.5.1查询运费模板列表(未完

&#xff08;一&#xff09;代码编写 1.阅读需求&#xff0c;确保理解其中的每一个要素&#xff1a; 获取全部运费模板&#xff1a;这意味着我需要从数据库中查询所有运费模板数据。按创建时间倒序排序&#xff1a;这意味着查询结果需要根据模板的创建时间进行排序&#xff0…

嵌入式学习-IO进程-Day02

嵌入式学习-IO进程-Day02 标准IO函数接口 fread&#xff0c;fwrite 文件指针偏移函数 文件IO 概念 文件IO的特点 文件描述符 文件IO的函数接口 open 打开文件 close 关闭文件 read 读函数 write 写函数 lseek 移动文件指针 标准IO和文件IO对比 目录操作函数 opendir 打开目录 c…

库卡ForceTorqueControl(一)

1. 功能说明 ForceTorqueControl 是一个可后载入的备选软件包&#xff0c;具有下列功能&#xff1a; 执行取决于测得的过程力和力矩的运动 遵守过程力和力矩&#xff0c;不取决于工件的位置和尺寸 遵守加工工件期间复杂的过程力变化 沿着根据测得的过程力编程的轨迹调整速度 通…

【高分论文密码】AI赋能大尺度空间模拟与不确定性分析及数字制图

随着AI大语言模型的广泛应用&#xff0c;大尺度空间模拟预测与数字制图技术在不确定性分析中的重要性日益凸显。这些技术已经成为撰写高分SCI论文的关键工具&#xff0c;被誉为“高分论文密码”。大尺度模拟技术能够从不同的时空尺度揭示农业生态环境领域的内在机理和时空变化规…

JAVA开源项目 课程智能组卷系统 计算机毕业设计

本文项目编号 T 009 &#xff0c;文末自助获取源码 \color{red}{T009&#xff0c;文末自助获取源码} T009&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 老…

【JAVA毕业设计】基于Vue和SpringBoot的医院电子病历管理系统

本文项目编号 T 008 &#xff0c;文末自助获取源码 \color{red}{T008&#xff0c;文末自助获取源码} T008&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 医…

python自动化办公实例(使用openpyxl、os处理统计Excel表中的数据并将其合并)

源数据格式 以其中一个表格为例 可以看到表中数据比较杂乱且并没有我们想要的数据、指标&#xff08;如一等奖、二等奖的数量&#xff09;不利于下一步数据的分析。所以我们需要手动对数据进行一些处理&#xff0c;大致格式如下&#xff1a; 数据处理格式 这里的手动处理可以…

基础算法(6)——模拟

1. 替换所有的问号 题目描述&#xff1a; 算法思路&#xff1a; 从前往后遍历整个字符串&#xff0c;找到问号之后&#xff0c;尝试用 a ~ z 的每一个字符替换即可 注意点&#xff1a;需考虑数组开头和结尾是问号的边界情况 代码实现&#xff1a; class Solution {public …

《深度学习》OpenCV FisherFaces算法人脸识别 原理及案例解析

目录 一、FisherFaces算法 1、什么是FisherFaces算法 2、原理 3、特点 4、算法步骤 1&#xff09;数据预处理 2&#xff09;特征提取 3&#xff09;LDA降维 4&#xff09;特征投影 5&#xff09;人脸识别 二、案例解析 1、完整代码 运行结果&#xff1a; 一、Fish…

【题解】【记忆化递归】——Function

【题解】【记忆化递归】——Function Function题目描述输入格式输出格式输入输出样例输入 #1输出 #1 提示数据规模与约定 1.思路解析2.AC代码 Function 通往洛谷的传送门 题目描述 对于一个递归函数 w ( a , b , c ) w(a,b,c) w(a,b,c) 如果 a ≤ 0 a \le 0 a≤0 或 b ≤…

阿里Dataworks使用循环节点和赋值节点完成对mongodb分表数据同步

背景 需求将MongoDB数据入仓MaxCompute 环境说明 MongoDB 100个Collections&#xff1a;orders_1、orders_2、…、orders_100 前期准备 1、MongoDB数据源配置 需要先保证DW和MongoDB网络是能够联通的&#xff0c;需要现在集成任务中配置MongoDB的数据源信息。 具体可以查…

项目分析:自然语言处理(语言情感分析)

在这个信息爆炸的时代&#xff0c;我们每天都在与海量的文本数据打交道。从社交媒体上的帖子、在线评论到新闻报道&#xff0c;文本信息无处不在。然而&#xff0c;这些文本不仅仅是文字的堆砌&#xff0c;它们背后蕴含着丰富的情感和观点。如何有效地理解和分析这些情感&#…

Linux下的防病毒软件(Antivirus software for Linux)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

FFmpeg的简单使用【Windows】--- 指定视频的时长

目录 功能描述 效果展示 代码实现 前端代码 后端代码 routers 》users.js routers 》 index.js app.js 功能描述 此案例是在上一个案例【FFmpeg的简单使用【Windows】--- 视频混剪添加背景音乐-CSDN博客】的基础上的进一步完善&#xff0c;可以先去看上一个案例然后再…

docker环境安装mongoDB实现平滑迁移实战

docker环境安装mongoDB实现平滑迁移实战 一、备份原始数据&#xff08;从别的服务器备份到当前服务器&#xff09;二、数据迁移三、迁移过程日志打印四、验证迁移数据准确性 一、备份原始数据&#xff08;从别的服务器备份到当前服务器&#xff09; 使用mongodump工具对原始mo…

Java发送请求实现QPS限制

业务场景 在开发中&#xff0c;当有业务需求需要调用第三方服务实现功能&#xff0c;但是服务接口有QPS限制&#xff0c;所以我们需要在发送请求时限制发送频率防止请求失败。 实现方法 使用 Java Semaphore 类来实现控制请求QPS QPS限制 Component public class QPSControll…