什么是serice:
Service可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC) (可以通过将服务声明为私有服务,并阻止其他应用访问)。
Service一般分为两种形式,一种用于执行一些下载文件等操作,不需要与用户进行交互,当应用组件(如Activity)通过调用 startService() 启动服务后,服务便与启动它的组件已无关联,服务会一直在后台运行,直到它负责的任务完成,服务会自动停止运行。一种是与应用组件进行绑定(调用bindService()),比如要做一个后台播放音乐,界面UI变化需要和音乐进度交相呼应的时候,就需要让服务与该应用界面进行绑定。多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
服务可以同时以这两种方式运行,它既可以是启动服务(以无限期运行),也允许绑定。只要实现了onStartCommand()(允许组件启动服务)和 onBind()(允许绑定服务)这一组回调方法。注意:服务是不会自己开辟一个新线程的,若执行一些耗时操作,请手动开辟一个新线程。
何时使用服务:
服务是一种即使用户未与应用交互,但它仍可以在后台运行的组件。如需在主线程外部执行工作,不过只是在用户正在与应用交互时才有此需要,则应创建新线程而非服务。若只想在一个activity运行的同时,则可在 onCreate() 中创建线程,在 onStart() 中启动线程,然后在 onStop() 中停止线程,或者用AsyncTask 或 HandlerThread,而非传统的 Thread 类。使线程与activity同存亡即可,不必开启一个服务。
如何实现service:
为了确保应用的安全性,请始终使用显式 Intent 启动或绑定 Service,且不要为服务声明 Intent 过滤器。 启动哪个服务存在一定的不确定性,而如果对这种不确定性的考量非常有必要,则可为服务提供 Intent 过滤器并从 Intent 中排除相应的组件名称,但随后必须使用 setPackage() 方法设置 Intent 的软件包,这样可以充分消除目标服务的不确定性。还可以通过添android:exported 属性并将其设置为 "false",确保服务仅适用于您的应用。
创建服务的两种方法:
1.Service:这是适用于所有服务的基类。
Intent intent = new Intent(this, myService.class);
startService(intent);//以此方式启动,无法获知service做什么
Intent intent = new Intent(this, myService.class);
bindService(intent,serviceConnection, BIND_AUTO_CREATE);//BIND_AUTO_CREATE表示创建尚未激活的服务.其他可能值为 BIND_DEBUG_UNBIND 和 BIND_NOT_FOREGROUND或0(表示无)。
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
//Android 系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法。
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyBinder) service;
//myBinder是该活动和服务相通的地方,但在执行此代码之前,活动生命周期需已变为可见
} };
public class myService extends Service {
@Override
public IBinder onBind(Intent intent) {
return myBinder;//回调,提供给活动MyBinder的对象
}
public class MyBinder extends Binder {
//可供绑定的activity调用的方法
//个人浅见,此类中的方法有点类似于接口的作用,仅代表用来和活动通信,切勿将过多的逻辑代码放在里面。影响程序的可读性
} }
unbindService(mConnection);//当客户端被销毁时,它将取消与服务的绑定,但始终应该在完成与服务的交互或Activity 暂停时取消绑定,以便服务能够在未被占用时关闭。
stopService(intent);//记得将后台程序关闭,特别是又启动又绑定时。
绑定是异步的。bindService()会立即回,“绝对不会”使IBinder返回客户端。要接收IBinder,客户端必须创建一个ServiceConnection实例,并将其传递给 bindService()。ServiceConnection 包括一个回调方法,系统通过调用它来传递 IBinder。
注意:1.要时刻记得service要想更改UI时,要用Handler,因为他们身处两个线程中。
2.只有 Activity、服务和内容提供程序可以绑定到服务,广播接收器无法绑定到服务。
2.IntentService:这是 Service 的子类,它使用工作线程逐一处理所有启动请求。如果不要求服务同时处理多个请求,这是最好的选择。 只需实现 onHandleIntent() 方法即可,该方法会接收每个启动请求的 Intent。
IntentService 执行以下操作:
•创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。
•创建工作队列,用于将一个 Intent 逐一传递给 onHandleIntent() 实现,这样永远不必担心多线程问题。
•在处理完所有启动请求后停止服务,因此不必调用 stopSelf()。
•提供 onBind() 的默认实现(返回 null)。
•提供 onStartCommand() 的默认实现,可将 Intent依次发送到工作队列和onHandleIntent() 实现。
只需要一个构造函数和一个 onHandleIntent() 实现即可。并且无需从中调用超类的唯一方法就是 onBind()(仅当服务允许绑定时,才需要实现该方法)。
public class MyService extends IntentService {
public MyService() {
super("MyService");
}
@Override
protected void onHandleIntent(Intent intent) {
//我们通常会做一些工作,比如下载一个文件。为示例,我们只睡5秒。
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
} } } }
服务的生命周期:
服务生命周期(从创建到销毁)可以遵循两条不同的路径:
1.启动服务:该服务在其他组件调用 startService() 时创建,然后无限期运行,且必须通过调用 stopSelf() 来自行停止运行,或者其他组件通过调用 stopService() 来停止服务。服务停止后,系统会将其销毁。
2.绑定服务:该服务在另一个组件调用 bindService() 时创建。然后,客户端通过 IBinder 接口与服务进行通信。客户端可以通过调用 unbindService() 关闭连接。多个客户端可以绑定到相同服务,而且当所有绑定全部取消后,系统即会销毁该服务。 (服务不必自行停止运行。)
这两条路径并非完全独立。例如,可以通过使用 Intent(标识要播放的音乐)调用 startService() 来启动后台音乐服务。随后,Activity 可以通过调用 bindService() 绑定到服务。在这种情况下,除非所有客户端均取消绑定,否则 stopService() 或 stopSelf() 不会真正停止服务。
通过实现这些方法,您可以监控服务生命周期的两个嵌套循环:
•服务的整个生命周期从调用 onCreate() 开始起,到 onDestroy() 返回时结束。与 Activity 类似,服务也在 onCreate() 中完成初始设置,并在 onDestroy() 中释放所有剩余资源。
•服务的有效生命周期从调用 onStartCommand() 或 onBind() 方法开始。每种方法均有 Intent 对象,该对象分别传递到 startService() 或 bindService()。
对于启动服务,有效生命周期与整个生命周期同时结束(即便是在 onStartCommand() 返回之后,服务仍然处于活动状态)。对于绑定服务,有效生命周期在 onUnbind() 返回时结束。
注:尽管启动服务是通过调用 stopSelf() 或 stopService() 来停止,但是该服务并无相应的回调(没有 onStop() 回调)。因此,除非服务绑定到客户端,否则在服务停止时,系统会将其销毁—onDestroy() 是接收到的唯一回调。
图 2 说明了服务的典型回调方法。尽管该图分开介绍通过 startService() 创建的服务和通过 bindService() 创建的服务,但是请记住,不管启动方式如何,任何服务均有可能允许客户端与其绑定。因此,最初使用 onStartCommand()(通过客户端调用 startService())启动的服务仍可接收对 onBind()的调用(当客户端调用bindService() 时)。
IntentService与Service
1. IntentService比Service好在哪?
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
2. IntentService 为什么可以处理耗时任务?
应该从源码上面来分析,IntentService 是直接继承与 Service的,内部在 onCreate()时,新建了一个HandlerThread 实例。
(HandlerThread 是一个Thread的 子类,HandlerThread 内部 有点线我们的UI线程,内部一个Looper loop循环一直轮询消息 获得消息 处理消息。)
而IntentService, 内部有一个Handler子类 ServiceHandler,它的Looper用的是这个HandlerThread 的Looper,IntentSerivce 在onStart()通过发送Message,ServiceHandler在处理Message 调用的是 onHandleIntent。
所以简单的说一个IntentService,内部就创建了一个线程,通过Android提供的 Handler Message Looper,这些消息处理的类构成了一个消息处理的模型。所以IntentService 的onHandleIntent 这个方法其实是在IntentService 中开辟的一个子线程中处理的。