Service
Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于:Service一直在后台运行,它没有用户界面,所以绝不会到前台来。一旦Service被启动起来之后,它就与Activity一样。它完全具有自己的生命周期。关于程序中Activity与Service的选择标准是:如果某个程序组件需要在运行时向用户呈现某种界面,或者该程序需要与用户交互,就需要使用Activity,否则就应该考虑使用Service了。
开发者开发Service的步骤与开发Activity的步骤很像,开发Service组件需要先开发一个Service的子类,然后在AndroidManifest.xml文件中配置该Service,配置时可通过
Service简介
Service组件也是可执行的程序,它也有自己的生命周期。创建、配置Service与创建、配置Activity的过程基本相似。
创建、配置Service
就像开发Activity需要两个步骤,开发Service也需要两个步骤:
- 定义一个继承Service的子类。
- 在AndroidManifest.xml文件中配置该Service。
Service与Activity还有一点相似之处,它们都是从Context派生出来的,因此它们都可调用Context里定义的如getResources()、getContentResolver()等方法。
与Activity相似的是,Service中也定义了系列生命周期方法,如下所示。
- abstract IBinder onBind(Intent intent):该方法是Service子类必须实现的方法。该方法返回一个IBinder对象,应用程序可通过该对象与Service组件通信。
- void onCreate():当该Service第一次被创建后将立即回调该方法。
- void onDestroy():当该Service被关闭之前将会回调该方法。
- void onStartCommand(Intent intent, int flags, int startId):该方法的早期版本是void onStart(Intent intent, int startId),每次客户端调用startService(Intent)方法启动该Service时都会回调该方法。
- boolean onUnbind(Intent intent):当该Service上绑定的所有客户端都断开连接时将会回调该方法。
下面的类定义了第一个Service组件。
public class FirstService extends Service { public FirstService() { } // 必须实现的方法 @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } // Service被创建时回调该方法 @Override public void onCreate() { super.onCreate(); System.out.println("Service is Created"); } // Service被启动时回调该方法 @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("Service is Started"); return START_STICKY; } // Service被关闭之前回调 @Override public void onDestroy() { super.onDestroy(); System.out.println("Service is Destroyed"); }}
定义了上面的Service之后,接下来需要在AndroidManifest.xml文件中配置该Service,配置Service使用
从上面的配置片段不难看出,配置Service与配置Activity的差别并不大,只是配置Service使用
启动和停止Service
下面的程序使用Activity作为Service的访问者,该Activity的界面中包含两个按钮,一个按钮用于启动Service,一个按钮用于关闭Service。
该Activity的代码如下。
public class MainActivity extends Activity { Button start, stop; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); start = (Button) findViewById(R.id.start); stop = (Button) findViewById(R.id.stop); // 创建启动Service的Intent final Intent intent = new Intent(); intent.setAction("tk.zongzhankui.firstservice.FIRST_SERVICE"); start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startService(intent); } }); stop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(intent); } }); }}
每当Service被创建时会回调onCreate方法,每次Service被启动时都会回调onStart方法——多次启动一个已有的Service组件将不会再回调onCreate方法,但每次启动时都会回调onStart方法。
绑定本地Service并与之通信
当程序通过startService()和stopService()启动、关闭Service时,Service与访问者之间基本上不存在太多的关联,因此Service和访问者之间也无法进行通信、数据交换。
如果Service和访问者之间需要进行方法调用或数据交换,则应该使用bindService()和unbindService()方法启动、关闭服务。
Context的bindService()方法的完整方法签名为:bindService(Intent service, ServiceConnection conn, int flags),该方法的三个参数的结束如下。
- service:该参数通过Intent指定要启动的Service。
- conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接成功时将回调该ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)方法;当访问者与Service之间断开连接时将回调该ServiceConnection对象的onServiceDisconnected(ComponentName name)方法。
- flags:指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定为0(不自动创建)或BIND_AUTO_CREATE(自动创建)。
注意到ServiceConnection对象的onServiceConnected方法中有一个IBinder对象,该对象即可实现与被绑定Service之间的通信。
当开发Service类时,该Service类必须提供一个IBinder onBind(Intent intent)方法,在绑定本地Servcie的情况下,onBind(Intent intent)方法所返回的IBinder对象将会传给ServiceConnection对象里onServiceConnected(ComponentName name, IBinder service)方法的service参数,这样访问者就可通过该IBinder对象与Service进行通信。
实际上开发时通常会采用继承Binder(IBinder的实现类)的方式实现自己的IBinder对象。
下面的程序示范了如何在Activity中绑定本地Service,并获取Service的运行状态。该程序的Service类需要“真正”实现onBind()方法,并让该方法返回一个有效的IBinder对象,该Service类的代码如下。
public class BindService extends Service { private int count; private boolean quit; // 定义onBinder方法所返回的对象 private MyBinder binder = new MyBinder(); // 通过继承Binder来实现IBinder类 public class MyBinder extends Binder { public int getCount() { // 获取Service的运行状态:count return count; } } // 必须实现的方法 @Override public IBinder onBind(Intent intent) { System.out.println("Service is Binded"); // 返回IBinder对象 return binder; } // Service被创建时回调该方法 @Override public void onCreate() { super.onCreate(); System.out.println("Service is Created"); // 启动一条线程,动态地修改count状态值 new Thread() { @Override public void run() { while (!quit) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count++; } } }.start(); } // Service被关闭之前回调 @Override public void onDestroy() { super.onDestroy(); this.quit = true; System.out.println("Service is Destroyed"); } // Service被断开连接时回调该方法 @Override public boolean onUnbind(Intent intent) { System.out.println("Service is Unbinded"); return true; }}
上面Service类的粗体字代码实现了onBind()方法,该方法返回了一个可访问该Service状态数据(count值)的IBinder对象,该对象将被传给该Service的访问者。
上面程序通过继承Binder类实现了一个IBinder对象,这个MyBinder类是Service的内部类,这对于绑定本地Service并与之通信的场景是一种常见的情形。当然也可以为MyBinder类提供一个借口,或把MyBinder类定义成一个外部类的形式,这无关紧要。
接下来定义一个Activity来绑定该Service,并在该Activity中通过MyBinder对象访问Service的内部状态。该Activity的界面上包含三个按钮,第一个按钮用于绑定Service,第二个按钮用于解除绑定;第三个按钮用于获取Service的运行状态。该Activity的代码如下。
public class MainActivity extends Activity { Button bind, unbind, getServiceStatus; // 保持所启动的Service的IBinder对象 BindService.MyBinder binder; // 定义一个ServiceConnection对象 private ServiceConnection conn = new ServiceConnection() { // 当该Activity与Service连接成功时回调该方法 @Override public void onServiceConnected(ComponentName name, IBinder service) { System.out.println("--Service Connected--"); // 获取Service的onBind方法所返回的MyBinder对象 binder = (BindService.MyBinder) service; } // 当该Activity与Service断开连接时回调该方法 @Override public void onServiceDisconnected(ComponentName name) { System.out.println("--Service Disconnected--"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bind = (Button) findViewById(R.id.bind); unbind = (Button) findViewById(R.id.unbind); getServiceStatus = (Button) findViewById(R.id.getServiceStatus); // 创建启动Service的Intent final Intent intent = new Intent(); // 为Intent设置Action属性 intent.setAction("tk.zongzhankui.bindservice.BIND_SERVICE"); bind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 绑定指定Service bindService(intent, conn, BindService.BIND_AUTO_CREATE); } }); unbind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 解除绑定Service unbindService(conn); } }); getServiceStatus.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 获取并显示Service的count值 Toast.makeText(MainActivity.this, "Service的count值为:" + binder.getCount(), Toast.LENGTH_LONG).show(); } }); }}
对于Service的onBind()方法所返回的IBinder对象来说,它可被当成该Service组件所返回的回调对象,Service允许客户端通过该IBinder对象来访问Service内部的数据,这样即可实现客户端与Service之间的通信。
与多次调用startService()方法启动Service不同的是,多次调用bindService()方法并不会执行重复绑定。对于前一个实例程序,用户每单击“启动Service”按钮一次,系统就会回调Service的onStart()方法一次;对于这个实例程序,不管用户单击“绑定Service”多少次,系统只会回调Service的onBind()方法一次。
Service的生命周期
随着应用程序启动Service方式的不同,Service的生命周期也略有差异。