Service
的两种启动方式以及生命周期
第一种方式:
通过start方式开启服务
使用service的步骤:
- 定义一个类继承Service;
manifest.xml
文件中配置Service;- 使用
context.startService(Intent)
启动Service; - 不使用时,调用
context.stopService(Intent)
停止服务;
使用start方式启动的生命周期:
onCreate() -> onStartCommand() -> onDestory()
如果Service已经开启,不会重复回调onCreare()
,如果再次调用context.startService()
,Service会调用onStart()
或onStartCommand()
。停止Service调用context.stopService()
,停止的时候回调onDestroy()
销毁。
特点:
服务开启后就跟调用者(开启者)没有任何关系了。如果开启者退出或者挂了,服务还在后台长期的运行,开启者不能调用服务里面的方法。
第二种启动方式
通过bind的方式开启服务
使用Service的步骤:
- 定义一个类继承Service
- 在
manifest.xml
文件中注册service - 使用
context的bindService(Intent,ServiceConnection,int)
方法启动service - 不再使用时,调用
unbindService(ServiceConnection)
方法停止该服务
使用bind方式启动的生命周期:
onCreate() -- > onBind() --> onUnbind() -- > onDestroy()
特点:
bind方式开启服务,绑定服务,调用者挂了,服务也跟着挂掉。绑定着可以调用服务里面的方法。
本地服务(LocalService)
调用者和Service在同一个进程里,所以运行在主线程的main线程中。所以不能进行耗时操作,可以采用在Service里面创建一个Thread来执行任务。Service影响的是进程的生命周期,讨论与Thread的区别没有意义。
任何Activity都可以控制同一Service,而系统也只会创建一个对应Service的实例。
示例代码:
- 定义一个类继承Servive
class TestService : android.app.Service() {
private val TAG = "TestService"
override fun onCreate() {
super.onCreate()
Log.i(TAG, "onCreate")
}
override fun onStart(intent: Intent, startId: Int) {
super.onStart(intent, startId)
Log.i(TAG, "onStart")
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.i(TAG, "onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
//绑定服务时调用这个方法,返回一个IBinder对象
override fun onBind(intent: Intent): android.os.IBinder? {
Log.i(TAG, "onBind")
return TestBinder()
}
override fun onUnbind(intent: Intent): Boolean {
Log.i(TAG, "onUnbind")
return super.onUnbind(intent)
}
// 停止服务,通过调用Context.unbindService(),别忘了service也继承了Context类
override fun unbindService(conn: ServiceConnection) {
super.unbindService(conn)
Log.i(TAG, "unbindService")
}
//服务挂了
override fun onDestroy() {
super.onDestroy()
Log.i(TAG, "onDestroy")
}
inner class TestBinder : Binder() {
fun stopService(serviceConnection: ServiceConnection) {
unbindService(serviceConnection)
}
fun runTask() {
for (i in 0..9) {
Log.i(TAG, "service is opening")
}
}
}
}
- 在
manifest.xml
文件中注册
<service
android:name=".TestService"
android:exported="true">
<intent-filter>
<action android:name="com.test.myservice.TestService"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
- 绑定Service
class ServiceActivity : AppCompatActivity() {
private lateinit var serviceBinding: ActivityServiceBinding
private lateinit var intents: Intent
private lateinit var serviceConnection: TestServiceConnection
private lateinit var binder: TestService.TestBinder
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_service)
serviceBinding = DataBindingUtil.setContentView(this, R.layout.activity_service)
initView()
}
private fun initView() {
/**
* 开启服务
* */
start_service.setOnClickListener {
intents = Intent(this@ServiceActivity, TestService::class.java)
startService(intents)
}
/**
* 停止服务
* */
stop_service.setOnClickListener { stopService(intents) }
/**
* 绑定服务
* */
bind_service.setOnClickListener {
intents = Intent(this@ServiceActivity, TestService::class.java)
serviceConnection = TestServiceConnection()
bindService(intents, serviceConnection, Context.BIND_AUTO_CREATE)
}
/**
* 解绑服务
* */
unBind_service.setOnClickListener { unbindService(serviceConnection) }
}
internal inner class TestServiceConnection : ServiceConnection {
//这里的第二个参数IBinder就是Service中的onBind方法返回的
override fun onServiceConnected(name: ComponentName, service: IBinder) {
Log.i("TestService", "onServiceConnected")
binder = service as TestService.TestBinder
binder!!.runTask()
}
override fun onServiceDisconnected(name: ComponentName) {
Log.i("TestService", "onServiceDisconnected")
}
}
}
startService
生命周期
2018-12-03 15:07:53.921 14516-14516/com.test.myservice I/TestService: onCreate
2018-12-03 15:07:53.930 14516-14516/com.test.myservice I/TestService: onStartCommand
2018-12-03 15:07:53.930 14516-14516/com.test.myservice I/TestService: onStart
2018-12-03 15:07:56.097 14516-14516/com.test.myservice I/TestService: onDestroy
bindService
生命周期
2018-12-03 15:07:58.089 14516-14516/com.test.myservice I/TestService: onCreate
2018-12-03 15:07:58.090 14516-14516/com.test.myservice I/TestService: onBind
2018-12-03 15:07:58.091 14516-14516/com.test.myservice I/TestService: onServiceConnected
2018-12-03 15:07:58.091 14516-14516/com.test.myservice I/TestService: service is opening
2018-12-03 15:07:58.091 14516-14516/com.test.myservice I/TestService: service is opening
2018-12-03 15:08:01.082 14516-14516/com.test.myservice I/TestService: onUnbind
2018-12-03 15:08:01.083 14516-14516/com.test.myservice I/TestService: onDestroy
远程服务(AIDL)
调用者和Service
不在同一个进程中,Service
在单独的进程中的main线程,是一种跨进程通信方式。
绑定远程服务的步骤:
- 在服务的内部创建一个内部类,提供一个方法,可以间接调用服务的方法
- 把暴露的接口文件的扩展名改为
.aidl
文件 去掉访问权限 - 实现服务的
onbind()
,继承Bander
和实现aidl
定义的接口,提供给外界可调用的方法 - 在Activity中绑定服务
bindService()
- 在服务成功绑定的时候回调
onServiceConnected()
传递一个IBinder对象 - aidl定义的接口
.Stub.asInterface(binder)
调用接口里面的方法
示例代码:
- 定义一个Service
class ProcessService : Service() {
val TAG: String = "ProcessService"
override fun onBind(intent: Intent?): IBinder? {
return ProBinder()
}
fun methodInService() {
Log.i(TAG, "服务里的方法执行了")
}
inner class ProBinder :ProcessBinder.Stub(){
override fun invokeMethodInMyService() {
methodInService()
}
}
}
- 创建ProcessBinder.aidl 文件
interface ProcessBinder {
void invokeMethodInMyService();
}
- 调用远程服务
/**
*
* 绑定远程服务
* */
bind_process_service.setOnClickListener {
intentProcess = Intent(this, ProcessService::class.java)
processConnection = ProcessConnection()
bindService(intentProcess, processConnection, Context.BIND_AUTO_CREATE)
}
/**
* 调用服务方法
* */
onclick_pro_service.setOnClickListener {
proBinder.invokeMethodInMyService()
}
internal inner class ProcessConnection : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
//通过Stub得到接口类型
proBinder = ProcessBinder.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName) {
}
}
按运行地点分类 | 特点 | 优点 | 缺点 | 应用场景 |
---|---|---|---|---|
本地服务 | 1. 运行在主线程 2. 主线程被终止后,服务也终止 | 1. 节约资源 通信方便,在同一进程不需要IPC和aidl | 限制性大:主进程被终止,服务进程也会终止 | 需要依赖某个进程的服务,如音乐播放 |
远程服务 | 1. 运行在独立进程 2. 服务常驻在后台,不受其它Activity影响 | 灵活:服务常驻在后台,不受其它Activity影响 | 1. 消耗资源:单独进程 2. 使用aidl进行IPC复杂 | 系统级别服务 |
运行类型分类 | 特点 | 应用场景 |
---|---|---|
前台服务 | 在通知栏显示通知 (用户可以看到) | 服务使用需要让用户知道并进行相关操作,如音乐播放服务 (服务被终止的时候,通知栏的通知也会消失) |
后台服务 | 处于后台的服务 (用户无法看到) | 服务使用时不需要让用户知道并进行相关操作,如天气更新,日期同步 (服务被终止的时候,用户是无法知道的) |
按功能分类 | 特点 | 应用场景 |
---|---|---|
不可通信的后台服务 | 1. 用startService启动 2. 调用者退出service任然存在 | 该后台服务不进行任何通讯 |
可通信的后台服务 | 1. 用bindService启动 2. 调用者退出,随着调用者销毁 | 该后台服务需要进行通讯 |
IntentService
Intentservice
是Service的子类,比普通的Service 增加了额外的功能。
Service
本身存在两个问题:
Service
不会专门启动一条单独的进程,Service
与它所在应用位于同一个进程;Service
也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;
IntentService
特征:
- 会创建独立的worker线程来处理所有的Intent请求;
- 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
- 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
- 为Service的onBind()提供默认实现,返回null;
- 为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;