Service
生命周期
启动服务和绑定服务存在不同的生命周期:
- 大部分调用的生命周期方法是一样的,如onCreate()、onDestroy()等,并且无论是启动或是绑定多次同一个服务,onCreate()、onDestroy()等这些共用的生命周期方法也仅被调用一次。
- 区别:当使用startService()启动服务的时候,回调的是onStatrCommand()方法,而使用bindService()绑定服务的时候,回调的是onBind()方法,并且解除绑定的时候还会回调onUnbind()方法。
- 启动服务:如果一个Service被Android组件调用startService()方法启动,那么不管这个Service对象是否使用bindService()方法被访问者绑定过,该Service都会在后台运行。因为Android系统只会为一个Service服务创建一个实例,所以无论启动几次,onCreate()方法仅执行一次,但是每次启动都会执行onStartCommand()方法,一旦服务启动,不管访问者是否被销毁,服务将一直执行下去,除非被调用stopService()方法或者服务自身的stopSelf()方法,当然系统资源不足的时候,也有可能回收结束服务回收资源。
- 绑定服务:如果一个Service被某个Android组件调用bindService()方法绑定服务,同样因为一个Service只会被创建一个实例,所以不管bindService()被不同的组件调用几次,onCreate()方法都只被回调一次,转而还会执行onBind()方法进行Binder对象的绑定(每个对象只绑定一次,即多次bindService():只回调一次onBind())。在绑定连接被建立后,Service将一直运行下去,除非宿主调用unbindService()方法断开连接或者之前的宿主被销毁了,这个时候系统会检测这个Service是否存在宿主绑定,当宿主绑定的数量为0的时候,系统将会自动停止服务,对应的onDestroy()将被回调。
- 对于一个既使用startService()启动又使用bindService()绑定的服务,除非这个服务的两条生命周期均完结,否则不会被销毁。也就是说,在不考虑系统在资源不足的时候,主动回收资源销毁服务的情况下,使用startService()启动的服务,必须使用stopService()或是服务本身的stopSelf()停止服务,使用bindService()绑定的服务,必须使用unbindService()或是销毁宿主来解除绑定,否则服务一直运行。
Service的开发步骤
- 开发一个服务类,需要继承Service或者IntentService。
- 在AndroidManifest清单文件中注册Service组件。
- 在一个Android组件中启动这个开发的Service组件。
- 服务使用完成之后,需要停止这个服务。
继承Service
在onCreate()或onStartCommand()中定义业务代码。
清单文件的配置
如果开发的服务需要被外部应用操作,还需要配置<intent-filter/>节点,但是如果仅本程序使用,则无需配置它也可以;如果这个服务强制仅本应用操作,可以配置<service/>节点的android:exported属性为false,这样即使配置了<intent-filter/>,外部应用也无法操作这个服务,android:exported属性默认为true。
<application>
<!-- 普通的服务 -->
<serviceandroid:name=".Service1"></service>
<!-- 可被外部应用访问的服务 -->
<serviceandroid:name=".Service2">
<intent-filter>
<actionandroid:name="com.bgxt.Service2"/>
</intent-filter>
</service>
<!-- 无法被外部应用访问的服务 -->
<serviceandroid:name=".Service3" android:exported="false">
<intent-filter>
<actionandroid:name="com.bgxt.Service3"/>
</intent-filter>
</service>
</application>
在Activity中启动Service
- Unbound service:
使用startService(Intent)方法启动的服务,在服务的外部,必须使用stopService()方法停止,在服务的内部可以调用stopSelf()方法停止当前服务。
注意点:多次startService():多次回调onStartCommand()
- Bounded service:
Context的bindService()方法:bindService(Intent service,ServiceConnection conn,int flags)
service:通过Intent指定要绑定的Service。
conn:一个ServiceConnection对象,该对象用于监听访问者与Service对象的onServiceConnected()方法。
flags:指定绑定时是否自动创建Service。0不自动创建、BIND_AUTO_CREATE,自动创建。
ServiceConnection接口:
- void onServiceConnection(ComponentName name,IBinder service):绑定服务的时候被回调,在这个方法获取绑定Service传递过来的IBinder对象,通过这个IBinder对象,实现宿主和Service的交互。
- void onServiceDisconnected(ComponentName name):当取消绑定的时候被回调。但正常情况下是不被调用的,它的调用时机是当Service服务被意外销毁时,例如内存的资源不足时这个方法才被自动调用。(主动unBindService时该方法并不会被调用)
IBinder:(通信传递的钩子)
在Service中继承Binder自定义功能(获取Service数据),在Activity中定义该service.binder的引用,通过ServiceConnection接口的onServiceConnection(ComponentName name,IBinder binder)中的binder得到其引用指向的对象>>通过该Binder钩子,在Activity中获得了Service中的数据
注意点:如果绑定服务提供的onBind()方法返回为Null,则也可以使用bindService()启动服务,但不会绑定上Service,因此宿主的ServiceConnection.onServiceConnected()方法不会被执行,也就不存在于宿主与服务的交互。
前台Service
跨进程调用Service
系统Service
不被销毁的Service
为了保持一个Service示例常驻后台,需要考虑几个问题:
- 开机启动:Android系统开启的时候会发送一个action为android.intent.action.BOOT_COMPLETED的广播,只需要一个广播接受者来接受这个Action,然后在其中启动服务即可。
- 意外停止:对于意外停止的服务,可以在服务的onDestory()方法中重新启动服务,这样刚销毁又重新启动。
- 意外销毁:当Service被意外销毁的时候,会发布一个action为android.intent.action.PACKAGE_RESTARTED的广播,只需监听这个广播,在其中重新启动服务即可。
- 系统回收:系统在资源不足的情况下会回收资源,但是也是有一定的规则的,回收的资源必定是优先级低的资源,所以提高Service的优先级,也可以保证一定的常驻系统后台,服务的优先级可以在清单文件中,配置<service/>节点下的<intent-filter/>节点的时候增加android:priority属性,将其的数值设定的比较高,此处数值越高,优先级越高,上线为1000。
上面介绍的思路基本上已经涵盖了让Service不被销毁的主要内容,还有一种极端的情况,可以使服务一旦启动,将不会被销毁,那在配置服务的清单文件的时候,在<application/>节点中增加android:persistent属性,并将其设置为true。但是这是最极端的情况,也不推荐使用,因为如果系统中安装了大量常驻组件,将会影响系统的使用。
参考
- Android--Service之基础(网)(Service基本使用、绑定Service通信)
- Android--Service之提高 (网)(IntentService的使用、Service与Thread的区别、Service生命周期详解、前台服务、服务资源被系统意外回收处理办法、不被销毁的服务)
- Android--Service之绑定服务交互 (网)(使用IBinder接口、使用Messenger类、使用AIDL)