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

devtools/2024/10/20 23:44:03/

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


本章关键点总结 & 说明:

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

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

在Android中,startServicebindService是两种不同的服务(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场景中的startServicebindService为入口,开始分析。

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

2.1 startService启动模式相关入口(startService、stopService)

2.1.1 从activity.startServiceAMS.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();//关键方法:调用AMSstartService方法ComponentName cn = ActivityManagerNative.getDefault().startService(mMainThread.getApplicationThread(), service,service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());//...return cn;} catch (RemoteException e) {return null;}}

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

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

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

2.1.2 从activity.stopService到AMS.stopService

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

//Context 
public abstract boolean stopService(Intent service);

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

//ContextImpl//关键流程:step1public boolean stopService(Intent service) {warnIfCallingFromSystemProcess();return stopServiceCommon(service, mUser);}//关键流程:step2private boolean stopServiceCommon(Intent service, UserHandle user) {try {validateServiceIntent(service);service.prepareToLeaveProcess();//关键方法:调用AMS的stopService方法int res = ActivityManagerNative.getDefault().stopService(mMainThread.getApplicationThread(), service,service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());//...return res != 0;} catch (RemoteException e) {return false;}}

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

2.2 bindService启动模式相关入口(bindService、unbindService

2.2.1 从activity.bindServiceAMS.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();//关键方法:调用AMSbindService方法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,实际上最终就是调用到AMSbindService方法中。其中过程参考2.1.1节即可。

2.2.2 从activity.unbindServiceAMS.unbindService

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

//Context
public abstract void unbindService(@NonNull ServiceConnection conn)

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

//ContextImpl@Overridepublic void unbindService(ServiceConnection conn) {//...if (mPackageInfo != null) {IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(getOuterContext(), conn);try {//关键方法:调用AMS的unbindService方法ActivityManagerNative.getDefault().unbindService(sd);} catch (RemoteException e) {}} else {throw new RuntimeException("Not supported in system context");}}

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

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


http://www.ppmy.cn/devtools/127411.html

相关文章

Substrate 网络层深度解读:libp2p 助力去中心化点对点高效通信

区块链中需要高效的通信工具来确保节点之间的顺畅交互。而 libp2p 正是开发者在点对点通信中不可或缺的框架&#xff0c;提供了强大的模块化功能&#xff0c;使得去中心化网络中的消息传递变得更加灵活且安全。在 Substrate 中&#xff0c;libp2p 的集成帮助开发者轻松实现各种…

@RequestMapping对不同参数的接收方式

1、简单参数 1、参数名与形参变量名相同&#xff0c;定义形参即可接收参数&#xff0c;且会自动进行类型转换。 RequestMapping("/simple")public String simpleParam(String name,int age){String username name;int userAge age;System.out.println(username&…

Facebook的全球化战略:如何连接不同文化与市场?

Facebook&#xff0c;作为全球最大的社交媒体平台之一&#xff0c;其全球化战略的成功不仅在于技术创新&#xff0c;还在于深刻理解并尊重不同文化和市场的差异。自2004年创立以来&#xff0c;Facebook通过多种策略&#xff0c;不断拓展其在世界各地的影响力。本文将探讨Facebo…

分布式数据库环境(HBase分布式数据库)的搭建与配置

分布式数据库环境&#xff08;HBase分布式数据库&#xff09;的搭建与配置 1. VMWare安装CentOS7.9.20091.1 下载 CentOS7.9.2009 映像文件1.2启动 VMware WorkstationPro&#xff0c;点击“创建新的虚拟机”1.3在新建虚拟机向导界面选择“典型&#xff08;推荐&#xff09;”1…

chat_gpt回答:python使用writearray写tiff速度太慢,有什么快速的方法吗

如果你在使用 Python 的 tifffile 库&#xff08;或类似库&#xff09;写入 TIFF 文件时速度太慢&#xff0c;以下是几个加速写入的优化方法和替代方案&#xff1a; 1. 优化文件压缩设置 TIFF 支持压缩格式&#xff0c;但压缩过程可能非常耗时。如果你不需要压缩&#xff0c;…

科研绘图系列:R语言柱状图(histogram)

文章目录 介绍加载R包数据画图系统信息介绍 柱状图(Bar Chart),也称为条形图(Bar Graph),是一种常用的统计图表,用于展示不同类别的数据量。它由一系列垂直或水平的条形组成,每个条形的长度或高度代表相应类别的数值大小。 加载R包 library(tidyverse)# 显示中文 li…

linux命令复习

vim分为命令行模式&#xff0c;编辑模式&#xff0c;转义命令&#xff08;需要输入&#xff1a;&#xff09;模式 退出vim &#xff08;在转义命令模式下&#xff09; 退出vim &#xff1a;w保存&#xff1a;wq保存并退出&#xff1a;q不保存并退出&#xff1a;q!强制退出&…

vue 音频播放控件封装

<template> <div> <audio @timeupdate="updateProgress" controls ref="audioRef" style="display: none" > <source :src="audioUrl" type="audio/mpeg" /> 您的浏览器不支持音频播放 </audio&…