Service是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。
前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。
后台服务执行用户不会直接注意到的操作。例如,如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务。
当应用组件通过调用 bindService() 绑定到服务时,服务即处于绑定状态。绑定服务会提供客户端-服务器接口,以便组件与服务进行交互、发送请求、接收结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
服务是一种即使用户未与应用交互也可在后台运行的组件,因此,只有在需要服务时才应创建服务。
如果您必须在主线程之外执行操作,但只在用户与您的应用交互时执行此操作,则应创建新线程。如果您只是想在 Activity 运行的同时播放一些音乐,则可在 onCreate() 中创建线程,在 onStart() 中启动线程运行,然后在 onStop() 中停止线程。您还可考虑使用 AsyncTask 或 HandlerThread,而非传统的 Thread 类
如果您确实要使用服务,则默认情况下,它仍会在应用的主线程中运行,因此,如果服务执行的是密集型或阻止性操作,则您仍应在服务内创建新线程。
有人会说进程在后台的耗时是15S,这个时间是怎么来的?这个时间是在Framework中定义的,在包括UI线程和Service的liveLongtime已定义好了,在APP层是无法修改,除非你重新编译AOSP包,然后烧制一个新的rom,这个已涉及到包的定制。有兴趣可以自己查看aosp的源码
如要创建服务,您必须创建 Service 的子类(或使用它的一个现有子类)。在实现中,您必须重写一些回调方法,从而处理服务生命周期的某些关键方面,并提供一种机制将组件绑定到服务(如适用
当另一个组件(如 Activity)请求启动服务时,系统会通过调用 startService() 来调用此方法。执行此方法时,服务即会启动并可在后台无限期运行。如果您实现此方法,则在服务工作完成后,您需负责通过调用 stopSelf() 或 stopService() 来停止服务。
当另一个组件想要与服务绑定时,系统会通过调用 bindService() 来调用此方法。在此方法的实现中,您必须通过返回 IBinder 提供一个接口,以供客户端用来与服务进行通信。请务必实现此方法;但是,如果您并不希望允许绑定,则应返回 null。
首次创建服务时,系统会(在调用 onStartCommand() 或 onBind() 之前)调用此方法来执行一次性设置程序。如果服务已在运行,则不会调用此方法。
onDestroy()
当不再使用服务且准备将其销毁时,系统会调用此方法。服务应通过实现此方法来清理任何资源,如线程、注册的侦听器、接收器等。这是服务接收的最后一个调用。
如果组件通过调用 startService() 启动服务(这会引起对 onStartCommand() 的调用),则服务会一直运行,直到其使用 stopSelf() 自行停止运行,或由其他组件通过调用 stopService() 将其停止为止。
如果组件通过调用 bindService() 来创建服务,且未调用 onStartCommand(),则服务只会在该组件与其绑定时运行。当该服务与其所有组件取消绑定后,系统便会将其销毁。
如要声明服务,请添加
服务启动有两种方式,startService() 和bindService()
服务启动后,其生命周期即独立于启动它的组件。即使系统已销毁启动服务的组件,该服务仍可在后台无限期地运行。因此,服务应在其工作完成时通过调用 stopSelf() 来自行停止运行,或者由另一个组件通过调用 stopService() 来将其停止
startService后,Service先调用onCreate(),再调用onStartCommand,如果该服务已启动,再启动也只会调用onStartCommand()
var service: Intent = Intent(context, HelloService::class.java)
bind.btnStart.setOnClickListener {
startService(service)
}
当服务被销毁了,才会重新执行oncrete()
var service: Intent = Intent(context, HelloService::class.java)
bind.btnStop.setOnClickListener {
stopService(service)
}
如果你是继承了IntentService,那么将会调用到onHandleIntent。但是IntentService会自动调用ondestory()。也就是说,IntentService启动就是一套流程走完,然后调用stopSelf()
知道了Service与IntentService的工作流程,那么我们应该了解了如何去让Service为我们做一些耗时。
inline fun Service.showToast(msg:String) {Toast.makeText(applicationContext,msg,Toast.LENGTH_SHORT).show()}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
MyLog.log(TAG, "onStartCommand")
var bundle = intent?.extras;
var title=bundle?.getString("title","")
runOnUiThread {
showToast(title!!)
}
return super.onStartCommand(intent, flags, startId)
}
var service: Intent = Intent(context, HelloService::class.java)
var bundle=Bundle();
bundle.putString("title","nihao")
service.putExtras(bundle)
bind.btnStart.setOnClickListener {
startService(service)
}
inline fun IntentService.showToast(msg:String) {Toast.makeText(applicationContext,msg,Toast.LENGTH_SHORT).show()}
override fun onHandleIntent(intent: Intent?) {
MyLog.log(TAG, "onHandleIntent")
var bundle = intent?.extras;
var title=bundle?.getString("title","")
runOnUiThread {
showToast(title!!)
}
}
这里为类扩展了一个函数showToast();
但是IntentService,调用完,就会销毁。
绑定服务允许应用组件通过调用 bindService() 与其绑定,从而创建长期连接。此服务通常不允许组件通过调用 startService() 来启动它。
如需与 Activity 和其他应用组件中的服务进行交互,或需要通过进程间通信 (IPC) 向其他应用公开某些应用功能,则应创建绑定服务。
如要创建绑定服务,您需通过实现 onBind() 回调方法返回 IBinder,从而定义与服务进行通信的接口。然后,其他应用组件可通过调用 bindService() 来检索该接口,并开始调用与服务相关的方法。服务只用于与其绑定的应用组件,因此若没有组件与该服务绑定,则系统会销毁该服务。您不必像通过 onStartCommand() 启动的服务那样,以相同方式停止绑定服务。
通过以上我们可以了解到,数据的获取,在onBind获取。如果想要和其他交互,可以通过IBinder。
override fun onBind(p0: Intent?): IBinder? {
bind = MyBinder().asBinder()
bindOne=MyTestBind()
MyLog.log(TAG, "onBind")
return bindOne
}
有人很好奇,这个IBinder如何获取?甚至有人了解AIDL,这个和AIDL有什么?其实Service是一个服务,在Android体系中,所有的service同学都是通过Binder。又因为Activity归AMS管理,AMS想要和Service通讯,就需要Binder来接入,我们想要和谁通讯,就需要获取这个对象的Binder,这就是他的信使,把我们的信息交给信使。
直接通过通过快捷键new一个。
创建完,删除里面生成的代码,写入自己的代码,记住:AIDL是接口,所有在使用要小心,准好以后,build->make一下项目,IDE会自动创建对象的JAVA文件。如果对AIDL还不懂,可以查下这篇文章:
Android Binder,AIDL跨进程通讯详解与实现,看一遍就懂_蜗牛、Z的博客-CSDN博客
inner class MyBinder : HelloServiceBinder.Stub() {
var info: String = ""
override fun add(msg: String?) {
showToast("add收到你的${msg}")
info = msg!!
}
override fun getTitle(): String {
return "我已收到你的${info}"
}
}
private inner class MyConnect : ServiceConnection {
override fun onServiceConnected(component: ComponentName?, bind: IBinder?) {
if (bind is HelloService.MyBinder) {
bind.add("onServiceConnected")
showToast(bind.title)
} else if (bind is HelloService.MyTestBind) {
bind.add("发送消息")
showToast(bind.getTitle())
}
}
override fun onServiceDisconnected(p0: ComponentName?) {
showToast("断开")
}
}
这样,就可以通过IBinder来和service交互。
这就很简单了,直接继承Binder。
inner class MyTestBind : Binder() {
var info: String = ""
fun add(msg: String?) {
showToast("add收到你的${msg}")
info = msg!!
}
fun getTitle(): String {
return "我已收到你的${info}"
}
}
1.startService与bindService的对比
2.bindService:可以多次bindService,但是onBind只会调用一次,但是解绑UNBindService只有一次,否则会报错。所以在绑定与解绑回调的时候,可以通过一个字段记录,方便操作绑定,