Service是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可以绑定到服务,以与之进行交互,甚至是进程间通信。
服务基本上分为两种形式:
启动 当应用组件通过startService()启动服务时,服务处于启动状态,一旦启动服务,它即可在后台无期限运行,即使启动服务的组件被销毁也不受影响。已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。
绑定 当应用组件通过bindService()绑定到服务时,服务即处于”绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互,发送请求,获取结果,甚至是利用进程间通信跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
服务可以以两种方式同时运行,需实现onStartCommand()和onBind()方法。
服务在其托管进程的主线程中进行,它既不创建自己的线程,也不在单独的进程中运行。如果服务将执行任何CPU密集型工作或阻止性操作,则应在服务器内创建新线程来完成这项工作。
要创建服务,需要创建Service的子类,重写回调方法,处理服务生命周期的某些关键方面并提供一种机制将组件绑定到服务。
onStartCommand(): startService()启动服务时,系统将调用此方法。如果实现此方法,则在服务完成后,需要使用stopSelf()或stopService()来停止服务。
onBind(): 当另一个组件想通过调用bindService()与服务绑定时,系统将调用此方法,在此方法的实现中,需要通过返回IBinder提供一个接口,供客户端用来与服务进行通信。
onCreate(): 首次创建服务时,调用此方法来进行一次性设置,如果服务已经在运行,则不会调用此方法。
onDestory(): 当服务不在使用且将被销毁时,系统将调用此方法,服务应该实现此方法来清理所有资源,如线程,注册的侦听器,接收器等。这是服务接收的最后一个调用。
为了确保应用的安全性,请始终使用显式Intent启动或绑定Service,且不要为服务声明Intent过滤器。
从传统上讲,可以扩展两个类来创建启动服务:
Service:适用于所有服务的基类。扩展此类时,必须创建一个用于执行所有服务工作的新线程,因为默认情况下,服务将使用应用的主线程,这会降低应用正在运行的所有Activity的性能。IntentService:Service的子类,它使用工作线程逐一处理所有启动请求。只需要实现onHandleIntent()方法,该方法会接受每个启动请求的Intent。IntentService执行以下操作:
创建默认的工作线程,用于在应用的主线程外执行传递给onStartCommand()的所有Intent。创建工作队列,用于将Intent逐一传递给onHandleIntent()实现。在处理完所有启动请求之后停止服务,不必调用stopSelf()。提供onBind()的默认实现(返回null)提供onStartCommand()的默认实现,可将Intent依次发送到工作队列和onHandleIntent()实现。使用IntentService显著简化了启动服务的实现。但是,若要求服务执行多线程(而不是通过工作队列处理启动请求),则可扩展Service类来处理每个Intent。
此例子与上个例子功能相同。
onStartCommand()方法返回一个整形数,必须是以下常量之一:
START_NOT_STICKY:如果系统在onStartCommand()返回后终止服务,则除非有挂起Intent要传递,否则系统不会重建服务。安全,避免在不必要的时候以及应用能够轻松重启所有未完成的作业时运行服务。START_STICKY:如果系统在onStartCommand()返回后终止服务,则重建服务并调用onStartCommand(),但不会重新传递最后一个Intent。除非有挂起Intent要启动服务,否则系统会通过空Intent调用onStartCommand(),适用于不执行指令,但无限期运行并等待作业的媒体播放器等。START_REDELIVER_INTENT:如果系统在onStartCommand()返回后终止服务,则会重建服务,并传递最后一个Intent调用onStartCommand()。适用于主动执行应该立即恢复的作业的服务(例如下载文件)。调用stopSelf(); 或另一组件使用stopService();
在使用stopSelf(int)时传入ID号,可以在处理多个请求时,避免出现处理完所有请求之前就停止服务,导致有请求不能执行的问题。
绑定服务允许应用组件通过调用bindService()与其绑定,以便建立长期连接。如需与Activity和其他应用组件中的服务进行交互,或者通过进程间通信向其他应用公开某些应用功能,则应创建绑定服务。
要创建绑定服务,必须实现onBind回调方法以返回IBinder,用于定义与服务通信的接口,然后,其他应用组件可以调用bindService来检索该接口,并开始对服务调用方法。如果没有组件绑定服务,则服务会销毁。
客户端完成与服务的交互后,调用unbindService取消绑定。
客户端可通过调用bindService绑定到服务,调用时,它必须提供ServiceConnection的实现,后者会监控与服务器的连接。BindService方法会立即无值返回,但当系统创建客户端与服务器之间的连接时,会对ServiceConnection调用onServiceConnected,向客户端传递用来与服务通信的IBinder。 多个客户端可连接到同一个服务,不过只有在第一个客户端绑定时,系统才会调用服务的onBind方法来检索IBinder,随后无需再次调用onBind,便可将同一IBinder传递至任何其他绑定的客户端。
创建提供绑定的服务时,必须提供IBinder,用以提供客户端用来与服务进行交互的编程接口,您可以通过三种方法定义接口:
扩展Binder类:如果服务是应用专用,并且与客户端在相同的进程中运行,则应该通过扩展Binder类并从onBind返回一个实例来创建接口。不以这种方式创建接口的唯一原因是,服务被其他应用或不同的进程占用。使用Messenger:如需让接口跨不同的进程工作,则可使用Message为服务创建接口。服务可以这种方式定义对应于不同类型Message对象的Handler。此Handler是Message的基础,后者随后可与客户端分享一个IBinder,从而让客户端能利用Message对象向服务发送命令。此外,客户端还可定义自有Messenger,以便服务回传消息。使用AIDL:(Android接口定义语言)执行所有将对象分解成原语的工作,操作系统可以识别这些原语并将它们编组到各进程中,以进行进程间通信。设置方法如下: 1. 在服务中创建一个满足下列任意要求的Binder实例:包含客户端可调用的公共方法;返回当前Service实例,其中包含客户端可调用的公共方法;或返回由服务承载的其他类的实例,其中包含客户端可调用的公共方法。 2. 从onBind回调方法返回此Binder实例。 3. 在客户端中,从onServiceConnected回调方法接收Binder,并使用提供的方法调用绑定服务。
扩展Binder类的实现实例
首先从Service扩展一个自己的LocalService类
public class LocalService extends Service { //声明一个Binder用于信息交互 private final IBinder mBinder = new LocalBinder(); private final Random mGenerator = new Random(); //绑定时返回绑定的Binder @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } //服务中的自定义方法 public int getRandomNumber(){ return mGenerator.nextInt(100); } public class LocalBinder extends Binder { LocalService getService(){ //为客户端提供公共方法,返回一个Service的当前实例 return LocalService.this; } } }再将Activity与Service绑定
public class ServiceActivity extends Activity { LocalService mLocalService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button btnBindService = new Button(this); btnBindService.setText("绑定服务"); setContentView(btnBindService); btnBindService.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(mBound){ //从Service中调用方法,如果有需要挂起的功能,那这个请求应该在工作线程中进行。 int num = mLocalService.getRandomNumber(); Toast.makeText(ServiceActivity.this, "num:"+num, Toast.LENGTH_SHORT).show(); } } }); } /** * 服务绑定的回调,将作为参数传递给BindService方法 */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { LocalService.LocalBinder binder = (LocalService.LocalBinder) service; mLocalService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName name) { mBound = false; } }; @Override protected void onStart() { super.onStart(); //绑定LocalService Intent intent = new Intent(this,LocalService.class); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); //解绑服务 if(mBound){ unbindService(mConnection); mBound = false; } } }建立一个使用了Messenger的Service类。
public class MessengerService extends Service { static final int MSG_SAY_HELLO = 1; //自定义Handler类 class IncomingHandler extends Handler{ @Override public void handleMessage(Message msg) { switch(msg.what){ case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "Hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } //定义Messenger对象并传入自定义Handler final Messenger mMessenger = new Messenger(new IncomingHandler()); @Nullable @Override public IBinder onBind(Intent intent) { //服务绑定时调用 Toast.makeText(getApplicationContext(),"binding", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } }在Activity使用
public class MessengerActivity extends Activity { Messenger mService = null; boolean mBound; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //从这里将Message生成 mService = new Messenger(service); mBound = true; } //断开连接 @Override public void onServiceDisconnected(ComponentName name) { mService = null; mBound = false; } }; public void sayHello(View v){ if(!mBound)return; Message msg = Message.obtain(null,MessengerService.MSG_SAY_HELLO,0,0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } //绑定服务 @Override protected void onStart() { super.onStart(); bindService(new Intent(this,MessengerService.class),mConnection,BIND_AUTO_CREATE); } //解绑服务 @Override protected void onStop() { super.onStop(); if(mBound){ unbindService(mConnection); mBound = false; } } }当我们使用bindService绑定一个服务,服务会调用onBind方法,来返回一个IBinder,但是客户端无法直接得到。 要得到IBinder对象,需要在bindService方法中传递一个ServiceConnection对象,在它的onServiceConnection方法中来获取IBinder对象。
客户端绑定到服务的步骤有:
实现ServiceConnection.调用bindService方法,传入ServiceConnection对象.当系统调用onServiceConnection方法时可以使用自定义接口操作服务。断开绑定用unbindService();