在android组件中,service一是用于在后台处理一些不需要user看到的事件,比如有一些只有在AP启动的时候才听的action,可以动态的在service里来监听,动态注册receiver,还有一些需要receiver来驱动的事件,由于receiver不适合处理复杂耗时的逻辑,可以start service来做UI显示前的处理,在需要和适合显示的时候才发消息给UI 来显示。再一个就是返回bind接口供AP 来调用需要的API 。那么首先第一个问题,怎么启动一个service呢?
启动一个service有两种方式,context.startService() and context.bindService(),下面就分别介绍一下。
1. Start service.
private void startSimpleService() {
Log.d(TAG, "startSimpleService ****");
Intent service = new Intent(this, MySimpleService.class);
this.startService(service);
}
调用startService后会做些什么呢?首先如果service还没有create,系统会调用service的onCreate(),然后onStartCommand(),这个时候service处于foreground状态,具有比较高的优先级,不会被系统kill掉。在2.0之前的版本里会用到onStart()这个api,但是之后的版本里这个api就被弃用了,因为android是系统来管理内存的,在系统内存紧张的时候会根据优先级kill掉一些优先级比较低的进程,而service在start后就不再是foreground状态,优先级就会降低,这个时候就容易被系统kill掉,而在2.0之前的版本,service在被系统kill掉之后,在系统内存不紧张的时候被restart,这个时候service的onCreate被调用,但是onStart并不会被调用,因为没有startService,这个时候就会比较尴尬,service create了,但是却没事做,也不知道什么时候stop。因此在2.0之后的版本里使用了onStartCommand()
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.d(TAG, "onStartCommand =====");
return Service.START_STICKY;
}
不同的地方是,它可以return一个int值,START_STICKY,START_NOT_STICKY,START_REDELIVER_INTENT.
START_STICKY: 和原来的onStart类似,在被系统kill掉后会restart,但是不同的是onStartCommand会被调用并传入一个null值作为intent,这个时候service就可以对这种case做出处理。
START_NOT_STICKY: 被kill掉后就不会自动restart了。
START_REDELIVER_INTENT: 如果service被kill掉了,系统会把之前的intent再次发送给service,直到service处里完成。
还有一点就是setforeground()这样的api也被弃用了,foreground状态是具有比较高的优先级的,有些开发者为了避免自己的service由于优先级太低被系统kill掉,就一直让自己的service跑在foreground状态,这显然是不合适的,这样系统的自动回收机制就被废掉了,大量的service占用了资源却不能被kill掉。在后来的版本里foreground的要有一个notification通知User,有一个service在foreground状态。
最后,start的service必需在不需要的时候主动stop掉,避免占用太多资源。
2. bind service
可以得到从service返回的bind接口,从而可以调用接口中的api。如果service没有create,在第一个process bind上来的时候会create,在最后一个process unbind后会destroy掉,因此,在使用完后要及时的unbind,避免占用资源。和start不同,bind的时候会调用service的onBind接口。
//MySimpleService
public class MyBinder extends Binder {
public String getString() {
return "simple test";
}
}
private final MyBinder myBinder = new MyBinder();
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
Log.d(TAG, "onBind =====");
return myBinder;
}
//MainActivity
MyBinder mBinder = null;
private ServiceConnection simpleConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
Log.d(TAG, "onServiceConnected ***");
mBinder = (MyBinder)service;
Log.d(TAG, mBinder.getString() + "****");
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.d(TAG, "onServiceDisconnected ***");
}
};
private void bindSimpleService() {
Intent service = new Intent(this, MySimpleService.class);
this.bindService(service, simpleConn, Service.BIND_AUTO_CREATE);
}
private void unbindSimpleService() {
this.unbindService(simpleConn);
}
最后需要说明一点,service不是一个子线程,如果有耗时的操作应该放到子线程里处理,如果service长时间被block,会有ANR的情况。