XJL's Blog

保持乐观、单纯。 要开心。

爱家人朋友,爱猫咪,爱学习。


Service 基础

Service 的分类:

按运行地点分类:本地服务远程服务

按运行类型分类:前台服务后台服务;

按功能分类:可通信服务不可通信服务

特点:

按运行地点分类:

类别 特点 优点 缺点 应用场景
本地服务(LocalService) 1,运行在主线程
2, 主线程被终止后,服务也会被终止。
1, 节约资源
2, 通信方便:由于在同一进程中因此不需要IPC1和AIDL。
限制性大:主进程被终止后,服务也会终止。 (最常用)需要依附某个进程的服务,例如音乐播放。
远程服务(RemoteService) 1, 运行在独立的进程
2, 服务常驻在后台,不受其他Activity的影响。
灵活,服务常驻后台,不受其他Activity 的影响。 1,消耗资源:单独进程
2,使用AIDL 进行IPC1复杂。
系统级别服务

按运行类型分类:

类别 特点 应用场景
前台服务 在通知栏显示通知(用户可以看到) 服务使用时需要让用户知道并进行相关操作,音乐播放并在状通知栏显示播放的音乐信息,并能进行一些操作。
后台服务 处于后台的服务(用户无法看到) 服务使用时不需要让用户知道并进行相关操作,如天气刷新,日期同步等。

按功能分类:

类别 特点 应用场景
不可通信的服务 1,用startService()启动
2,调用者退出后service 仍谈存在。
该后台服务不进行任何通信。
可通信的服务 1,用bindService()启动
2,调用者退出后,随着调用者一起被销毁。
该后台需要进行通信。

本地Service

具体使用步骤:

  • 步骤1:新建子类继承Service 类

    需要重写父类的onCreate()onStartCommand()onDestory()onBind()方法

  • 步骤2:构建用于启动Service 的Intent 对象

  • 步骤3:调用startService() 启动Service、调用stopService() 停止服务

  • 步骤4:在AndroidManifest.xml 中注册Service

AndroidManifext.xml 中Service 的常见属性说明

属性 说明 备注
android:name Service 的类名 -
android:label Service 的名字 如不设置,默认为Service 的类名
android:icon Service 的图标 -
android:permission 申明此Service 的权限 有提供了该权限的应用才能控制或者链接此服务
android:process 表明该服务是否在另一个进程中运行(远程服务) 不设置默认为本地服务; remote 则设置成远程服务
android:enabled 系统默认启动 true: Service 将会默认被系统启动;不设置默认为false
android:exported 该服务是否能够被其他应用程序所控制或连接 不设置默认此项为false

Service 的生命周期

Service 的5个生命周期方法:

onCreate()onStartCommand()onBind()onUnbind()onDestory()

Service 生命周期图示

只使用startService启动服务的生命周期

image

startService启动服务的生命周期

只使用BindService绑定服务的生命周期

image

BindService绑定服务的生命周期

同时使用startService()启动服务、BindService()绑定服务的生命周期

image

Activity 向Service通信

第一种方式:通过MyBinder 方式调用Service 方法

步骤(以购票举例):

  • 继承Binder 定义中间对象

    class TicketService : Service() {
      
        override fun onBind(intent: Intent?): IBinder? {
            return BuyTicketBinder()
        }
      
        public fun buyTicket(money: Int){
            //50元一张票,当money 大于等于时购票成功,否则失败
            if (money >= 50){
                Toast.makeText(this, "出票成功!", Toast.LENGTH_SHORT).show()
            }else {
                Toast.makeText(this, "票款不足,出票失败!", Toast.LENGTH_SHORT).show()
            }
        }
      
        inner class BuyTicketBinder : Binder() {
            public fun callBuyTicket(money: Int){
                buyTicket(money)
            }
        }
    }
    
  • 重写ServiceConnection, onServiceConnected 时调用中间人对象绑定服务

    class TicketActivity : AppCompatActivity() {
      
        var ticketBinder: TicketService.BuyTicketBinder ?= null
        var ticketConnection: TicketConnection ?= null
      
      
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_ticket)
            var intent: Intent = Intent(this, TicketService::class.java)
            //建立连接服务
            ticketConnection = TicketConnection()
            bindService(intent, ticketConnection!!, Context.BIND_AUTO_CREATE)
            //点击按钮开始购票
            findViewById<Button>(R.id.buy_ticket).setOnClickListener {
                ticketBinder?.callBuyTicket(40)
            }
        }
      
        //监听服务状态
        inner class TicketConnection : ServiceConnection{
      
            //断开连接
            override fun onServiceDisconnected(name: ComponentName?) {
                    Log.i("TicketConnection", "onServiceDisconnected")
            }
      
            //连接成功
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                Log.i("TicketConnection", "onServiceConnected")
                    ticketBinder = service as TicketService.BuyTicketBinder
            }
      
        }
      
        override fun onDestroy() {
            //当activity 销毁的时候 解绑服务
            super.onDestroy()
            ticketConnection?.let { unbindService(it) }
        }
      
    }
          
    

记得在AndroidManifest.xml 中注册TicketActivityTicketService

通过接口调用Service 方法

使用接口调用Service 和直接调用本质都是一样的,只不过多了接口的步骤。

步骤(依旧以上的购票为例子):

  • 继承Binder 定义中间人对象
  • 定义接口
interface TicketInterface {

    fun callBuyTicket(money: Int) //买票
    fun callRefundTicket() //退票

}
  • 重写ServiceConnectiononServiceConnected 时调用中间人对象,强制转换为接口(ticketBinder = service as TicketService.BuyTicketBinder)绑定服务

    详细代码如下:

    TicketActivityByInterface.kt:

      
    class TicketActivityByInterface : AppCompatActivity() {
      
        var ticketBinder: TicketServiceByInterface.BuyTicketBinder ?= null
        var ticketConnection: TicketConnectionByInterface ?= null
      
      
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_ticket)
            var intent: Intent = Intent(this, TicketServiceByInterface::class.java)
            //建立连接服务
            ticketConnection = TicketConnectionByInterface()
            bindService(intent, ticketConnection!!, Context.BIND_AUTO_CREATE)
            //点击按钮开始购票
            findViewById<Button>(R.id.buy_ticket).setOnClickListener {
                ticketBinder?.callBuyTicket(40)
            }
        }
      
        //监听服务状态
        inner class TicketConnectionByInterface : ServiceConnection{
      
            //断开连接
            override fun onServiceDisconnected(name: ComponentName?) {
                Log.i("TicketConnection", "onServiceDisconnected")
            }
      
            //连接成功
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                Log.i("TicketConnection", "onServiceConnected")
                ticketBinder  = service as TicketServiceByInterface.BuyTicketBinder
            }
      
        }
      
        override fun onDestroy() {
            //当activity 销毁的时候 解绑服务
            super.onDestroy()
            ticketConnection?.let { unbindService(it) }
        }
      
    }
      
    

    TicketServiceByInterface.kt:

    class TicketServiceByInterface : Service() {
      
        override fun onBind(intent: Intent?): IBinder? {
            return BuyTicketBinder()
        }
      
        public fun buyTicket(money: Int){
            //50元一张票,当money 大于等于时购票成功,否则失败
            if (money >= 50){
                Toast.makeText(this, "出票成功!", Toast.LENGTH_SHORT).show()
            }else {
                Toast.makeText(this, "票款不足,出票失败!", Toast.LENGTH_SHORT).show()
            }
        }
      
        inner class BuyTicketBinder : Binder(), TicketInterface {
            override fun callBuyTicket(money: Int) {
                buyTicket(money)
            }
      
      
            override fun callRefundTicket() {
               //TODO 退票方法就不做实现了
            }
      
        }
    }
    

Service 和Activity 通信总结:

方法一:

  • 新建服务继承自Service,并添加一个内部类继承自Binder

  • 覆写onBind 方法,返回步骤一中的Binder 对象
  • 调用的Activity 中添加一个内部类继承ServiceConnection , 在onServiceConnected中获取到Binder 对象并调用逻辑方法绑定服务

方法二:

  • 实现一个接口,并在Service 类的Binder 对象中继承该接口并实现相应方法,其他用方法一相同

源码中Binder 机制

该问题主要时说一下binder 干什么的,Service Manager是是如何成为一个守护进程的

Binder 是干什么的

Binder: 是一种进程间通信(IPC)机制,基于OpenBinder

  • Client、Server 和Service Manager 实现在用户空间中,Binder 驱动程序实现在内核空间中
  • Binder 驱动程序和Service Manager 在Android 平台中已经实现,开发者只需要在用户空间实现自己的Client 和Sercer
  • Binder 驱动程序提供设备文件/dev/binder 与用户空间交互,Client、Server 和Service Manager 通过open 和ioctl 文件操作函数与Binder 驱动程序进行通信
  • Client和Server之间的进程间通信通过Binder驱动程序间接实现
  • Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力

未完待续。。。

  1. IPC(Inter-Process Communication,进程间通信)。  2

最近的文章

Android 学习笔记目录

Activity 相关知识学习笔记Fragment-相关知识学习笔记Android Jetpack 使用入门算法与数据结构笔记Android 知识点汇总to be continue……

继续阅读
更早的文章

Fragment 相关知识学习笔记

Fragment 生命周期Fragment 生命周期的11个方法: onAttach(), onCreate(), onCreateView(), onActivityCreated(), onStart(), onResume(), onPause(), onStop(), onDestoryView(), onDestory(), onDetach() Fragment 的生命周期和Activity 很相似,只是多了一下方法:onAttach(): 在Fragment 和Activi...…

继续阅读