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组件 -->
<service android:name=".FirstService">
<intent-filter>
<!-- 为该Service组件的intent-filter配置action -->
<action android:name="tk.zongzhankui.firstservice.FIRST_SERVICE">
</intent-filter>
</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的生命周期也略有差异。