为什么 bindService 能和 Activity 的生命周期联动?

2023-11-07

前言

之前做一道面试题:startService 和 bindService 有什么不同?为什么 bindService 能和 Activity 的生命周期联动?

前一个问题可以很快回答出来:生命周期不同,结束方式不同,交互方式不同。

后一个问题也能很快想到应该是 Activity 在销毁的时候顺带把 Service 销毁了。那么为什么 startService 不行呢?具体是怎么实现的呢?如果不对源码研究一番,似乎无法给出让人信服的回答,于是就有了这篇文章。

启动和绑定的区别

无论是启动 Activity,还是 Service,基本的流程都是 Context -> ActivtityManagerService -> 某些中间类(Activity 是 ActivityStarter、ActivityStack 等,Service 是 ActiveServices) -> ActivityThread。具体的代码流程比较长,而且很多和本文要探讨的主题无关,因此这里不会详细分析启动或绑定的流程,而只会保留与本文相关的部分源码。

startService

从 ContextImpl 的 startService 方法开始说起:

class ContextImpl extends Context {

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
    
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            // 检查 Intent
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // 启动 Service
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());
            // 检查结果
            if (cn != null) {
                ...
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    
}

ActivityManager.getService() 返回的就是 AMS 本身,而 AMS 只起到一个中转的作用,除了一些参数判断之外,AMS 直接调用了 ActiveServices 的 startServiceLocked:

public final class ActiveServices {

    final ActivityManagerService mAm;

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {

        // 和 Activity 同样有一个 Record 记录对应的组件
        ServiceRecord r = res.record;
        
        ... // 主要是检查,发现错误则抛出异常,或返回 null 等结果

        // 设置 ServiceRecord 的数据域
        r.lastActivity = SystemClock.uptimeMillis();
        r.startRequested = true;
        r.delayedStop = false;
        r.fgRequired = fgRequired;
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants, callingUid));
                
        ... // 主要是检查,发现错误则抛出异常,或返回 null 等结果

        // 启动
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }
}

好了,startService 的流程暂时分析到这里,后面也没什么特别的,最后还是会由 ActivityThread 来创建 Service 对象,回调相关的生命周期方法等。

bindService

下面看 bindService 的实现:

class ContextImpl extends Context {

    final @NonNull LoadedApk mPackageInfo;
    private final @Nullable IBinder mActivityToken;

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                Process.myUserHandle());
    }
    
    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        ...
        IServiceConnection sd;
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        try {
            // 这个 token 是 Activity 启动时创建的,对应
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 bindService 能和 Activity 的生命周期联动? 的相关文章

  • 如何做Android - 滑动抽屉从左到右滑动..?

    如何将android滑动抽屉从LTR滑动 使用时android orientation horizontal 它从 RTL 滑出 我该如何进行 LTR 谢谢 我找到了答案表格 Here http blog sephiroth it 2011
  • 如何获取每个StorageVolume的可用大小和总大小?

    背景 谷歌 悲伤 计划破坏存储权限 https www xda developers com android q storage access framework scoped storage 这样应用程序将无法使用标准文件 API 和文件
  • 从响应中获取标头(Retrofit / OkHttp 客户端)

    我正在使用 Retrofit 与 OkHttp 客户端和 Jackson 进行 Json 序列化 并希望获取响应的标头 我知道我可以扩展 OkClient 并拦截它 但这发生在反序列化过程开始之前 我基本上需要的是获取标头以及反序列化的 J
  • 如何正确释放Android MediaPlayer

    我正在尝试向我的 Android 应用程序添加一个按钮 当点击该按钮时它会播放 MP3 我已经让它工作了 但没有办法释放 mediaPlayer 对象 因此即使在我离开活动后它仍然会继续播放 如果我在react 方法之外初始化MediaPl
  • 按下按钮时应用不同的样式

    有没有办法在按下按钮时将样式应用于按钮 如果我有一种风格样式 xml
  • 如何更改终端的默认目录?

    我想更改 Android Studio v2 2 2 终端的默认目录 当我打开终端时 它基于项目的目录 C 项目路径 我经常需要使用adb shell 所以我必须导航到 SDK 路径 平台工具 才能使用 adb 命令 是否可以更改终端的默认
  • Dialog.setTitle 不显示标题

    我正在尝试向我的对话框添加自定义标题 但是每当我运行我的应用程序时 它都不会显示标题 我创建对话框的代码是 final Dialog passwordDialog new Dialog this passwordDialog setCont
  • java.lang.IllegalStateException:应用程序 PagerAdapter 更改了适配器的内容,而没有调用 PagerAdapter#notifyDataSetChanged android

    我正在尝试使用静态类将值传递给视图 而不是使用意图 因为我必须传递大量数据 有时我会收到此错误 但无法找出主要原因是什么 Error java lang IllegalStateException The application s Pag
  • 在 android 中建立与 MySQL 的池连接

    我需要从我的 Android 应用程序访问 MySQL 数据库 现在所有的工作都通过 DriverManager getConnection url 等等 但我必须从多个线程访问数据库 所以我必须使用连接池 问题1 是 com mysql
  • Android:后台Activity可以执行代码吗?

    后台的活动是否被视为 正在运行 并且可以执行代码 还是处于挂起状态 他们暂停了 活动生命周期 http developer android com reference android app Activity html ActivityLi
  • 从 BroadcastReceiver 类调用活动方法

    我知道我可以做一个内部接收器类来调用接收器中的任何方法 但我的主要活动太大了 要做的事情也很多 因此 我需要一个扩展广播接收器的类 但它不是内部类 并且可以从我的主要活动中调用一种方法 我不知道是否可能 但我的活动是家庭活动和 single
  • logcat 中 mSecurityInputMethodService 为 null

    我写了一点android应显示智能手机当前位置 最后已知位置 的应用程序 尽管我复制了示例代码 并尝试了其他几种解决方案 但似乎每次都有相同的错误 我的应用程序由一个按钮组成 按下按钮应该log经度和纬度 但仅对数 mSecurityInp
  • OnLongClickListener 不工作

    我有一个ImageView 我需要使用onLongClickListener对于图像视图 当我使用这段代码时 什么也没有发生 Code gallery Gallery findViewById R id gall1 gallery setA
  • 您使用什么物理 Android 设备进行测试?

    有什么好的推荐用于测试目的的物理 Android 设备吗 我正在苹果阵营寻找像 iPod touch 这样的设备 可以帮助 iOS 开发人员测试他们的东西 我知道有 Nexus One 但那东西相当昂贵 而且我并不真正关心手机的东西 而是可
  • Android:无法使用 DbHelper 和 Contract 类将数据插入 SQLite

    public class Main2Activity extends AppCompatActivity private EditText editText1 editText2 editText3 editText4 private Bu
  • Android 如何将总天数准确更改为年、月、日?

    我正在做一个应用程序 该应用程序与根据给定的生日日期输入获取一个人的年龄有关 为此 我从下面的代码中获取从该日期到当前日期的总天数 String strThatDay 1991 05 10 SimpleDateFormat formatte
  • 卡片视图 单击卡片移至新活动

    我是 Android 编程新手 正在研究卡片布局 我想知道如何使其可点击 android clickable true android foreground android attr selectableItemBackground 我的卡
  • 如何检查 Android 中的同步设置

    我正在构建一个 Android 应用程序 我需要检查设备中注册的每个单独帐户的同步设置 我知道我可以通过 ContentResolver 类来做到这一点 但我遇到了一些问题 我已设法获取设备上所有帐户的列表 但我不知道在运行时从哪里获取特定
  • 插件“Android Bundle Support”不兼容

    大家好 自从上次更新以来 当我启动 android studio 时 我遇到了一个非常奇怪的错误 我有这个错误 插件错误 插件 Android Bundle Support 不兼容 直到构建 AI 195 SNAPSHOT 我在网上找不到任
  • Android 后台倒计时器

    我有一个 Android 应用程序 它管理一个倒计时器 类 CountDownTimer 它显示在应用程序屏幕中 以显示到达 00 00 还剩多少时间 我现在的问题是 当我按主页按钮或启动另一个应用程序时 应用程序 计时器不会在后台运行 所

随机推荐

  • echarts X轴像直尺一样设置刻度

    在做老师的项目的时候 老师让我们实现X轴的直尺刻度显示 网上查了查相关代码 大家都没有明确介绍 因此我在这里记录一下 自己的学习 先看实现效果 对echarts的xAxis yAxis这两个属性进行修改即可实现 xAxis 第一个 是原X轴
  • npm install、npm install --save与npm install --save-dev (转)

    仅供学习参考 侵权删 以npm安装msbuild为例 npm install msbuild 会把msbuild包安装到node modules目录中 不会修改package json 之后运行npm install命令时 不会自动安装ms
  • qml学习之qwidget与qml结合使用并调用信号槽交互

    学习qml系列之一 说明 学习qml系列之qwiget和qml信号槽的交互使用 并在qwidget中显示qml界面 在qml中发送信号到qwidget里 在qwidget里发送信号给qml 在qwidget里面调用qml界面方式 方式一 使
  • 测试与开发模型

    测试与开发模型 测试的工作流程 1 需求分析 gt 2 测试计划和测试方案 gt 3 测试用例设计 gt 4 测试用例执行 gt 5 评估阶段 测试报告 1 需求分析 分许需求的点 参与需求评审 快速熟悉项目 2 测试计划和测试方案 计划
  • tq210-kernel 4.1.33移植(1)基本移植

    这篇文章讲述一个新的kernel的移植 1 到kernel org下载4 1 33 修改顶层Makefile ARCH arm CROSS COMPILE arm Linux 根据自己的环境修改交叉编译器前缀 如果发现 tmp cc8nFJ
  • 【Attention机制】YOLOX模型改进之(SE模块、ECA模块、CBAM模块)的添加

    文章目录 YOLOX模型改进 模块简介 SE模块 SE模块的具体介绍 插入位置 主要代码 CBAM模块 插入位置 主要代码 目的动机 ECA模块 插入位置 主要代码 模块添加 建立attention py 修改yolo pafpn py文件
  • 在Macbook Pro上为TensorFlow设置GPU

    最近忽然发现自己的Macbook Pro上装有一块额外的NVIDIA GeForce GT 750M显卡 于是蠢蠢欲动想装一个TensorFlow 试试在GPU上跑算法的性能 先进入TensorFlow官网的Mac安装页面 发现要先装一堆N
  • 循环语句

    for循环 for循环其实本质上与while循环本质上是一样的 标准形式 for 语句1 表达式的初始化 语句2 测试条件 语句3 执行更新 语句内容 关于for循环的结构 语句1是表达式是初始化 只会在程序开始的时候执行一次 语句2是判断
  • EMC测试项分类

    EMC包含两大项 EMI 干扰 和 EMS 敏感度 抗干扰 EMI测试项包括 RE 辐射 发射 CE 传导干扰 Harmonic 谐波 Flicker 闪烁 EMS测试项包括 ESD 静电 EFT 瞬态脉冲干扰 DIP 电压跌落
  • linux 日志 硬件检测,在Linux上分析硬件检测日志

    数据库管理员在数据库的运维过程中或多或少要和操作系统乃至硬件打上交道 分析数据库故障时操作系统日志往往也是一个重要的线索来源 以Linux操作系统为例 其主要的日志子系统 syslog subsystem 可大致分为三类 即1 用户连接日志
  • IKE主模式及预共享密钥认证配置实验

    一 组网和实验环境 按如上的接口ip先作配置 本文实验采用的交换机是H3C模拟器 下载地址如下 http forum h3c com forum php mod viewthread tid 109740 highlight H3C E6
  • L1-018 大笨钟(java)

    1 题目详情 微博上有个自称 大笨钟V 的家伙 每天敲钟催促码农们爱惜身体早点睡觉 不过由于笨钟自己作息也不是很规律 所以敲钟并不定时 一般敲钟的点数是根据敲钟时间而定的 如果正好在某个整点敲 那么 当 数就等于那个整点数 如果过了整点 就
  • kerberos认证系统服务器,基于Kerberos认证的NFS服务器搭建

    NFS是Linux下常用的共享软件 v3版本不太安全 无法进行用户认证 这里简单说明一下V4版本和Kerberos配合实现认证访问的过程 0 准备工作 跟之前的Kerberos一样 需要3台机器来做试验 很多资料上写的是两台 即kdc ni
  • 2022年11月14日--11月25日(ue4 tf1视频教程+socket视频教程+cesium for ue源码抄写,本周10小时,合计1747小时,剩余8253小时)

    工作内容中有高并发 我感觉cesium for ue除了例子外 很难突破 所以把网络视频教程学下 学习不是难事 难的是没有资料 从0到1 目前 mysql 7 1 tf1 4 4 oss 12 1 蓝图反射 1 7 moba 1 5 web
  • 【解决新手爬虫 python3】UnicodeEncodeError: ‘gbk‘ codec can‘t encode character ‘‘ in position

    解决新手爬虫遇到的UnicodeEncodeError gbk codec can t encode character xa0 in position 7084 illegal multibyte sequence 起初的代码 from
  • Qt程序图标

    网络上有很多这方面的介绍 这里只是MARK一下 程序图标说明 准备 1 图标文件 ICO图标文件 也许需要BMP PNG转ICO工具 2 资源文件 RC文件 可手动创建一个空的RC文件 注 这两个文件应与工程文件 PRO 放在同一路径下 步
  • 编写一个函数计算传入字符串中数字、字母、空格以及其它字符的个数

    编写一个函数计算传入字符串中数字 字母 空格以及其它字符的个数 def num str1 a b c d 0 for i in str1 if i isdigit a 1 elif i isalpha b 1 elif i isspace
  • 记录一次生产环境Net Core应用内存暴涨导致OOM的排查过程

    事情起源于某个周五 刚开始是突然发现生产服务不能访问 请求时居然直接提示服务器拒绝响应 然后连用于管理生产环境的Portainer虽然能打开 但登录右上角直接出红色告警信息无法接收服务器信息 进去后所有的node都不显示 生产环境跑了二年多
  • XCTF黑客精神解题报告

    题目来源 https adworld xctf org cn 解题环境 kali frida 12 8 0 Win10 IDA PRO 7 0 整体思路 静态分析 dex 应用的核心思路为com gdufs xman MyAPP类中最先执行
  • 为什么 bindService 能和 Activity 的生命周期联动?

    前言 之前做一道面试题 startService 和 bindService 有什么不同 为什么 bindService 能和 Activity 的生命周期联动 前一个问题可以很快回答出来 生命周期不同 结束方式不同 交互方式不同 后一个问