1、Service的生命周期
onCreate()
首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand()或onBind() 之前)。如果服务已在运行,则不会调用此方法,该方法只调用一次
onStartCommand()
当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。(在绑定状态下,无需实现此方法。)
onBind()
当另一个组件想通过调用 bindService() 与服务绑定时,将调用此方法。在此方法的实现中,必须返回 一个IBinder 接口的实现类,供客户端用来与服务进行通信。无论是启动状态还是绑定状态,此方法必须重写l。
onDestroy()
当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。
2、前台Service配合Notification
startForeground(int id, Notification notification) 该方法的作用是把当前服务设置为前台服务,其中id参数代表唯一标识通知的整型数,需要注意的是提供给 startForeground() 的整型 ID 不得为 0,而notification是一个状态栏的通知。
Intent ii = new Intent(this,MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this,0,ii,0);
// 设置通知属性
Notification nf = new NotificationCompat.Builder(this)
.setContentTitle("title")
.setContentText("content")
.setWhen(System.currentTimeMillis())
.setContentIntent(pi)
.build();
// 设置为前台服务
startForeground(1,nf);
stopForeground(boolean removeNotification) 该方法是用来从前台删除服务,此方法传入一个布尔值,指示是否也删除状态栏通知,true为删除。 注意该方法并不会停止服务。 但是,如果在服务正在前台运行时将其停止,则通知也会被删除。
@Override
public void onDestroy() {
//移除前台服务
if (isRemove) {
stopForeground(true);
}
isRemove=false;
super.onDestroy();
}
3、Service与Activity通信
绑定状态下Service可以通过IBinder与Activity进行通信 MyService中的代码如下
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
class MyBinder extends Binder{
}
public Object getData(){
return new Object();
}
}
MyActivity中的代码如下:
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MyService mService = (MyService) iBinder;
// 获取数据
Object dataFromService = mService.getData();
// 处理数据
dealWithData(dataFromService);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
// 失败处理
showFail();
}
启动状态下可以通过广播进行通信
在Activity中注册广播
MyReceiver mr = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SERVICE_RECEIVER);
registerReceiver(msgReceiver, intentFilter);
在Service中携发送广播
public void communicate(){
Intent i = new Intent(SERVICE_RECEIVER);
i.putExtra("name","value");
sendBroadcast(i);
}
4、Service与线程
1) 两者的应用场景
当要执行耗时的网络请求或者数查询以及其他阻塞UI线程的任务时,都可以使用工作线程。
而对于长时间在后台运行而且不需要交互的任务(如:播放音乐),可以通过Service+Notification实现后台执行同时在通知栏显示。
2)两者的结合
由于Service的代码是运行在主线程中,所以在执行一些耗时的操作应该在Service具体的方法中开启一个子线程,一些常见的套路可以是Service在后台执行+Notification在通知栏显示+Thread异步执行任务。
2.1)IntentService
IntentService封装了Handler和HandlerThread,在onCreate方法中创建HandlerThread然后用它的Looper构建一个Handler,而在onHandleIntent方法执行结束之后,IntentService采用stopSelf(startId)来停止服务,主要是为了避免出现消息还没有处理完而又停止服务的尴尬情况。由于IntentService继承自Service且拥有较高的优先级,不易被系统杀死,所以在执行一些高优先级的异步任务的时候可以采用IntentService。
5、启动服务与绑定服务的转换
情况1:先绑定服务后启动服务
如果当前Service实例先以绑定状态运行,然后再以启动状态运行,那么绑定服务将会转为启动服务运行,这时如果之前绑定的宿主(Activity)被销毁了,也不会影响服务的运行,服务还是会一直运行下去,直到收到调用停止服务或者内存不足时才会销毁该服务。
情况2:先启动服务后绑定服务
如果当前Service实例先以启动状态运行,然后再以绑定状态运行,当前启动服务并不会转为绑定服务,但是还是会与宿主绑定,只是即使宿主解除绑定后,服务依然按启动服务的生命周期在后台运行,直到有Context调用了stopService()或是服务本身调用了stopSelf()方法或者内存不足时才会销毁服务。