当前位置: 首页 > news >正文

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.lryc.cn/news/461633.html

相关文章:

  • 深度学习:领域适应(Domain Adaptation)详解
  • 华三服务器R4900 G5在图形界面使用PMC阵列卡(P460-B4)创建RAID,并安装系统(中文教程)
  • Linux实验三
  • Vue预渲染:深入探索prerender-spa-plugin与vue-meta-info的联合应用
  • 使用`ThreadLocal`来优化鉴权逻辑并不能直接解决Web应用中session共享的问题
  • Python implement for PID
  • C++中的initializer_list类
  • 持续科技创新 高德亮相2024中国测绘地理信息科技年会
  • 深入理解HTTP Cookie
  • Python多进程编程:使用`multiprocessing.Queue`进行进程间通信
  • Docker 常见命令
  • Map 双列集合根接口 HashMap TreeMap
  • Pip源设置(清华源)相关总结
  • 编程入门攻略
  • C++核心编程和桌面应用开发 第十一天(静态转换 动态转换 常量转换 重新解释转换)
  • Ubuntu-Ubuntu22.04下Anacodna3的qmake和Qt的qmake冲突问题
  • mysql用户管理(user表列信息介绍,本质,管理操作),数据库的权限管理(权限列表,权限操作)
  • AI工具 | Notion全新AI集成:搜索、内容生成、数据分析与智能聊天功能发布
  • 微知-如何查看PCIe设备插入在哪个插槽以及对应的busid?(biosdecode)
  • 数据结构 —— 树和二叉树简介
  • ubuntu安装boost
  • 【Spring AI】Java实现类似langchain的第三方函数调用_原理与详细示例
  • CIM系统:智慧城市的数字基石
  • Android中Fragment的使用场景与生命周期
  • 输入网址后,浏览器是如何高效渲染出网页的?
  • springboot单文件,多文件下载方式
  • JIT详解
  • 线下陪玩导游系统软件源码,家政预约服务源码(h5+小程序+app)
  • 模拟退火算法最常见知识点详解与原理简介控制策略
  • C语言高效内存管理:对齐、缓存与位域