Service
Service正如其名,是一种服务性质的组件,不能被用户所见,只能在后台运行,但是可以和其他组件进行交互,Service可以看做不可见的Activity,可以在后台有规律的执行某些操作,Service组件与其他的应用程序对象一样,是运行在启动它的主线程中,所以不可以在Service中进行耗时的操作,会阻塞主线程,但是可以在Service中启动新线程来进行操作,Service作为没有界面的长生命周期组件,可以用于媒体播放,记录用户地理位置信息等后台操作。
Service的启动模式
Service可以通过startService启动一个无绑定的Service,当启动这个Service的Activity被destroy的时候,Service继续运行在后台,不过这种方式启动的Service与Activity无交互,还有一种方式是通过bindService方法启动一个绑定的service,这种方式启动的Service可以与绑定的程序发生交互,但是在绑定的程序退出的时候,需要unbindService来解绑定,不然会有异常发生,还可以连续调用上面的两个函数,让Service同时具有上面两个的优点,当程序退出时,Service不销毁,而且可以与应用程序发生交互。
Service的生命周期
对于startService方式启动的服务来说,只有第一次启动的时候会调用onCreate() 方法,以后多次调用startService均只调用onStartCommand()方法(onStart()方法被弃用了),不论前面调用多少次startService,只需调用一次stopService即可停止服务,stopService多次调用没事,不会产生异常
对于bindService方式启动的服务来说,可以多次调用bindService,不过只有第一次有效,但是unbindService只能在服务正在运行的时候调用有效,当绑定服务没有运行的时候,调用此方法会产生异常

Service的使用
- 定义一个Service
定义一个Service,首先得继承android.app.Service,根据需要,覆写上面生命周期图中的回调函数
public class Service1 extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Log.v("x", "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("x", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.v("x", "onDestroy");
super.onDestroy();
}
}
可以看到,上面有一个特殊的onBind方法是必须覆写的,这个方法的默认返回null,如果通过startService方式启动Service,那么不用管这个回调函数,如果使用bindService启动服务,那么当绑定的时候,会回调这个函数,通过这个函数的返回值,启动服务的组件就可以与服务进行交互。
- 注册Service
与其他组件一样,当定义好一个Service以后,需要在配置文件中注册这个Service
<service android:name=".Service1" />
- 启动Service
startService启动:类似于其他组件,需要使用Intend对象
Intent intent = new Intent(); intent.setClass(this, Service1.class); startService(intent);
停止startService启动的服务
Intent intent = new Intent(); intent.setClass(this, Service1.class); stopService(intent);
bindService启动服务:
public boolean bindService (Intent service, ServiceConnection conn, int flags)
Intent service:一个Intent对象,用于指定启动的Service
ServiceConnection conn:一个ServiceConnection 对象,用于绑定时回调给绑定者
int flags:启动的标志,Service.BIND_AUTO_CREATE代表自动创建服务
Intent intent = new Intent(this, Service2.class); startService(intent); bindService(intent, conn, Service.BIND_AUTO_CREATE);
定义ServiceConnection 对象,ServiceConnection 是一个接口,我们需要new一个匿名内部类出来
ServiceConnection conn = new ServiceConnection() {
@Override
//当bind成功,onBind方法被调用以后调用此回调函数
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v("x", "Connected");
}
//当绑定意外断开的时候调用此方法
@Override
public void onServiceDisconnected(ComponentName name) {
Log.v("x", "onServiceDisconnected");
}
};
在ServiceConnection 的onServiceConnected()方法中,我们可以看到第二个参数为IBinder类型,这个参数就是Service中必须覆写的onBind方法的返回值,通过这个返回值,我们就可以获取服务的实例,从而调用服务中的方法。
完整的demo:
Service代码
public class Service2 extends Service {
//自定义一个类继承自Binder
class MyBinder extends Binder {
//自定义方法,返回此Service的实例
public Service2 getService() {
return Service2.this;
}
}
@Override
public IBinder onBind(Intent intent) {
//此函数的返回值就是ServiceConnection的第二个参数
return new MyBinder();
}
//Service自定义的四个方法
public void pro() {
Log.v("x", "pro");
}
public void stop() {
Log.v("x", "stop");
}
public void next() {
Log.v("x", "next");
}
public void play() {
Log.v("x", "play");
}
}
启动服务端的代码
public class MainActivity extends Activity {
private Service2 service2;
ServiceConnection conn = new ServiceConnection() {
@Override
//当bind成功,onBind方法被调用以后调用此回调函数
public void onServiceConnected(ComponentName name, IBinder service) {
//获取服务实例
service2 = ((Service2.MyBinder) service).getService();
}
//当绑定意外断开的时候调用此方法
@Override
public void onServiceDisconnected(ComponentName name) {
Log.v("x", "onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.bindService: {
Intent intent = new Intent(this, Service2.class);
startService(intent);
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
break;
case R.id.unbindService: {
unbindService(conn);
}
break;
case R.id.play:
service2.play();
break;
case R.id.next:
service2.next();
break;
case R.id.stop:
service2.stop();
break;
case R.id.pro:
service2.pro();
break;
}
}
}
将Service设置为前台可见
有时候,我们想让Service与用户产生交互,或者给用户提示,我们可以调用public final void startForeground (int id, Notification notification)方法,第一个参数为Notifycation的id,第二个参数为Notifycation对象,在onCreate中调用这个方法,那么Service将会用传入的Notifycation对象,产生一个通知栏提示。可以给与用户提示,onDestroy里面调用stopForeground可以解除前台运行但是不会停止服务,如果在服务被停止的时候,是前台运行状态,通知栏也会一起被清除,不管是否调用了stopForeground。