之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始将介绍应用程序无需界面交互的内部交互相关知识点,首先从另外一个四大组件之一的服务Service开始。

清单文件一文的组件声明中,已经知道服务Service与界面Activity一样,都要在清单文件中注册声明。同样的,每个注册声明的服务Service类向上追溯都必须继承自android.app.Service父类,因此服务Service也有自己的生命周期。

生命周期

Service主要负责应用程序中不需要界面展示或交互的长时间操作,像是播放音乐,网络请求等都是可以在服务Service中完成的。与界面Activity的生命周期一样,在服务Service的声明周期内不允许执行耗时操作,所以,虽然服务Service中可以进行长时间操作,但是仍然需要将这部分耗时操作放入非Android系统主线程中。

(调用构造方法)对象实例化

首次启动新的服务Service时,系统会申请内存空间存储该服务Service的实例化对象。服务Service两种启动方式,其一与界面Activity一样需要借助意图Intent对象,调用上下文环境Context对象的startService(Intent service)启动。

其二是进程间通信时所用的方式,不仅要借助意图Intent对象,还要使用实现android.content.ServiceConnection接口的对象,进而调用上下文环境Context对象的bindService(Intent service, ServiceConnection conn, int flags)方法,而参数三 flags 标记了启动该服务Service时所绑定的模式,通常使用Context.BIND_AUTO_CREATE标记会自动创建当前绑定的服务Service。除此之外,还可以按位或的形式追加其他标记,例如追加|Context.BIND_NOT_FOREGROUND标记当前绑定服务Service为较低优先级的后台服务,在手机息屏或高能耗时,系统会优先杀死低优先级的服务;而追加|Context.BIND_IMPORTANT标记可以提升绑定服务Service的优先级为前台服务,在手机息屏或高能耗时,只要当前应用程序存活,当前服务Service就不会被杀死;如果追加|Context.BIND_ABOVE_CLIENT标记当前绑定服务Service的优先级要高于当前应用程序,当手机息屏或高能耗时,系统可能会先杀死应用程序,但是当前服务Service仍然存活。

Android系统为不同进程间的通信提供了一套AIDL语言规范,详情将在以后的文章中介绍,这里只需了解在实现ServiceConnection接口中,要重写两个方法,分别是在进程通信接口与服务Service连接成功后回调的onServiceConnected(ComponentName name, IBinder service)方法,和连接断开之后回调的onServiceDisconnected(ComponentName name)方法。

上述两种启动方式,都会触发系统在当前应用程序的清单文件中查找对应注册过的服务Service,在找到之后,就会创建其实例化对象,如果在清单文件中没有找到对应的服务Service,将不会有任何错误或异常。

与启动未注册的服务Service不同的是,当调用startActivity()系列方法启动一个没有在清单文件中注册过的界面Activity时,系统通常会抛出android.content.ActivityNotFoundException异常。

(调用attachBaseContext(Context base))加载运行环境

由于Service也是android.content.ContentWrapper的子类,所以系统在创建服务Service的实例化对象后,也会优先对其加载上下文运行环境,将参数 base 作为当前应用程序的Context对象与该服务Service绑定。在该方法被调用之后的任意位置,就可以通过调用getBaseContext()等系列方法获取并使用当前服务Service所在的上下文环境了。

(调用onCreate())服务创建

在创建服务Service并加载运行环境之后,系统会优先调用该方法,表示当前服务已经完成创建。可以重写该方法执行一些服务内部使用的资源初始化操作。在执行完该方法之后,就标志着当前服务Service创建成功了,之后会一直处于运行状态,同时根据上述启动方式的不同,调用不同的生命周期方法。

(调用onStartCommand(Intent intent, int flags, int startId))服务启动

如果是通过上述启动方式一启动的服务Service,每调用一次startService(),系统都会调用一次该方法。

其中参数 intent 接收每次启动服务所传入的Intent意图。

参数 flags 标记当前服务多次启动状态,一般默认是 0 ;当该服务Service被首次调用该方法且成功返回Service.START_REDELIVER_INTENT=3后,莫名被系统杀死,之后再次启动该服务时,标记参数则是 Service.START_FLAG_REDELIVERY=1 ;如果该服务Service被首次调用该方法并未返回结果,系统将会再次尝试调用该方法,标记参数则为 Service.START_FLAG_RETRY=2

参数 startId 作为系统唯一值,以此标记当前服务Service

最终返回指定的int类型,如果返回默认的Service.START_STICKY_COMPATIBILITY=0,当系统杀死该服务Service后,再次调用startService()将不会再被系统回调该方法;另外如果返回Service.START_STICKY=1,在系统杀死该服务Service后,再次调用startService()将会被系统重新创建实例化并回调该方法。

(调用onBind(Intent intent))服务绑定

如果是通过上述启动方式二启动的服务Service,在首次调用bindService()后,系统会调用该方法,而之后如果多次调用bindService(),只有在当前服务Service已经执行完onUnbind()解绑的生命周期方法,并在解绑方法中返回 false 时,系统才会回调该方法。参数 intent 接收绑定服务所传入的Intent意图,最终返回android.os.IBinder接口的实现类对象。返回结果可以在bindService(Intent service, ServiceConnection conn, int flags)方法的参数二conn.onServiceConnected(ComponentName name, IBinder service)方法中接收,也就是其中的参数二IBinder类型的 service

服务解绑(调用onUnbind(Intent intent))

如果是通过上述启动方式二启动的服务Service,可以在bindService()绑定服务Service位置相对应的位置,调用unbindService()解绑服务Service。之后系统会回调该方法,同样的借助参数Intent意图实例来指定要解绑的指令信息。

服务重绑(调用onRebind(Intent intent))

如果是通过上述启动方式二启动的服务Service,如果当前服务Service已经执行完解绑生命周期,并在onUnbind()方法中返回 true 时,系统将会调用该方法以使用原有的IBinder对象重新绑定当前服务Service,因此该方法不需要返回值。其参数 intent 接收绑定服务所传入的Intent意图。最终返回值boolean类型,以标记当前服务再次被绑定时是否使用原有绑定过的IBinder对象。

服务销毁(调用onDestroy())

启动之后的服务Service会一直处于运行状态,直到系统可能因能耗过过而杀死低优先级的进程时,当前服务Service将会被动杀死,或者当前服务Service主动调用代码停止运行。与上述两种启动方式对应,服务Service也有两种停止方式

其一对应于startService()启动的服务,调用上下文环境Context对象的stopService(Intent service)方法停止运行,或者调用当前服务Service对象的stopSelf()方法也可以停止运行自身服务。

其二对应于bindService()绑定的服务,调用上下文环境Context对象的unbindService(ServiceConnection conn)方法解除绑定。由于绑定该服务的可以有多个ServiceCOnnection连接,所以必须每个bindService()绑定服务的位置都对应调用unbindService()方法主动解绑,以防止出现内存泄漏或资源占用等误操作。

在服务Service所有绑定已解绑或主动停止运行后,系统最终会调用该方法,之后将销毁内存中创建的该服务Service实例化对象。因此可以重写该方法,对应于onCreate()中申请的初始化资源在该方法中释放掉。


服务Service的生命周期与界面Activity有些类似,这也保证了在其中可以执行无用户交互的操作,那么针对这种应用场景还需要怎么构建子线程操作呢?而且服务Service的设计还可以进行进程间通信。具体又是如何编写代码搭建进程间的沟通桥梁呢?敬请期待后续文章。

Android系统编程入门系列之加载服务Service的更多相关文章

  1. Android系统编程入门系列之加载界面Activity

    上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...

  2. Android系统编程入门系列之界面Activity绘制展示

    上篇文章介绍了界面Activity的启动方式和生命周期,本篇将继续介绍在界面Activity中的内容是如何绘制展示给用户的. 在Android系统上运行新创建的界面Activtiy,给用户展示的是空白 ...

  3. Android系统编程入门系列之界面Activity响应丝滑的传统动画

    上篇文章介绍了应用程序内对用户操作响应的相关方法位置,简单的响应逻辑可以是从一个界面Activity跳转到另一个界面Activity,也可以是某些视图View的相对变化.然而不管是启动一个界面执行新界 ...

  4. Android系统编程入门系列之服务Service中的进程间通信

    在上篇文章以线程间的通信方式Handler类结尾,服务Service还支持的进程间通信,又是具体怎么实现的呢?这就要用到加载服务一文中提到的AIDL语言规范了. AIDL是 Android Inter ...

  5. Android系统编程入门系列之应用初始化Application

    在上一篇文章中我们了解到Android系统启动应用的时候,会首先加载AndroidManifest.xml清单文件中的一系列信息,在清单文件中如果不指定<application></ ...

  6. Android系统编程入门系列之硬件交互——通信硬件电信SIM卡

    现在的SIM卡通常具备基站定位.语音通话.短信消息.网络流量这四大功能,而在移动端是无法对SIM卡使用基站定位功能的,所以这里只介绍移动端如何使用SIM卡实现语音通话.短信消息.数据流量三个功能. 语 ...

  7. Android系统编程入门系列之应用环境及开发环境介绍

        作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...

  8. Android系统编程入门系列之界面Activity交互响应

    在上篇文章中已经了解到界面Activity的绘制完全依赖其加载的视图组件View,不仅如此,用户的每次触摸操作都可以在界面Activity内接收并响应,也可以直接传递给其中的某个视图View响应.本文 ...

  9. Android系统编程入门系列之界面Activity响应多元的属性动画

    在响应丝滑动画一篇文章中,分别介绍了作用于普通视图.绘制视图的绘制对象.和界面这三种对象的动画效果,但是都有一些使用的局限性.比如这些动画都只是以屏幕上绘制更新的方式绘制动画,并没有真实改变作用对象的 ...

随机推荐

  1. 1、JVM体系结构

    1.JVM跨语言的平台 随着java7的正式发布,java虚拟机的设计者们通过JSR-292规范基本实现在java虚拟机平台上运行非java语言编写的程序. java虚拟机根本不关心运行在其内部的程序 ...

  2. 『动善时』JMeter基础 — 50、使用JMeter测试WebSocket接口

    目录 1.什么是WebSocket接口 2.为什么需要WebSocket 3.测试WebService接口前的准备 4.WebSocket Sampler组件界面详解 5.使用JMeter测试WebS ...

  3. Linux中系统时间同步ntpdate简介

    Linux服务器运行久时,系统时间就会存在一定的误差,一般情况下可以使用date命令进行时间设置,但在做数据库集群分片等操作时对多台机器的时间差是有要求的,此时就需要使用ntpdate进行时间同步.所 ...

  4. Pytest学习笔记10-生成html报告

    前言 在pytest中,如何生成html测试报告呢,pytest提供了pytest-html插件,可以帮助我们生成测试报告,当然,如果希望生成更加精美的测试报告,我们还可以使用allure生成报告,下 ...

  5. 4.QT:spinbox(spindoublebox)控件的信号响应

    Qt的QSpinBox和QDoubleSpinBox两个控件在默认情况下是valueChanged信号,会响应每次输入栏的改变. 比如想要输入数值"123",我们会依次键入1 - ...

  6. [Linux]Ansible自动化运维① - 入门知识

    目录 一.Ansible 概述 1.1 Ansible 是什么 1.2 Ansible 优势 1.3 Ansible 特性 二.Ansible 入门 2.1 Ansible 架构 2.2 Ansibl ...

  7. linux学习之路第九天(任务调度)

    crond 任务调度 概念 任务调度:是指的系统在某个时间执行的特定命令或程序. 比喻理解: 可以这样理解,比如生活中有闹钟,闹钟的作用是不是叫人起床的,那古时候没有闹钟,叫人起床的工作是不是要人去完 ...

  8. 关于scrollview的无限滚动效果实现

    起因及需求:做过阅读器的朋友应该知道,一般的阅读器都会有仿真.平移等特效.最近赶上真空期,项目不忙,有点时间,于是想抓起来,总结点干货. 仿真翻页及平滑翻页的基本实现: 仿真翻页,使用系统自带的UIP ...

  9. Tomcat和Servlet简析

    目录 Servlet Tomcat 参考 Servlet Servlet通常指我们继承了Servlet接口的类,我们开发Servlet时一般就是继承HttpServlet重写它的doGet.doPos ...

  10. win10禁止粘滞键 禁止按5次shift开启粘滞键

    如果你感觉粘滞键的快捷键影响了你的使用或想强行更改连续按5次上档键的指向的话,建议用你需要的程序替换%windir%\system32文件夹下面的sethc.exe @echo offclsdel / ...