service是什么?
按照官方文档中的解释,Service是一个可以在后台执行长时间运行操作而不需要用户界面的应用组件。Service可由其他组件启动,即使用户切换到其他应用Service仍旧运行。另外组件也可以绑定到服务,并与之进行交互,甚至IPC通信。

Service的开启
- startService()
用户通过startService()启动服务时,服务就处于启动状态,一旦启动服务,服务即可在后台无线运行,即使启动服务的组件被销毁也不受影响。不会反回结果给调用方。
通过startService()开启的服务将会一直运行,直到使用stopSelf(),或由其他组件通过调用stopService()停止。 - bindService()
用户通过bindService()绑定到服务时,服务就处于"绑定"状态,绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果。仅当与另一个应用组件绑定时,绑定服务才运行。
多个组件可绑定到同一个服务上,全部取消绑定后,该服务就会被销毁。
- 注意
服务托管在主线程中运行,所以如果有耗时的操作,应创建新的线程来完成这项工作。
Service的回调方法
- onStartCommand()
当另一个组件通过startService()请求启动服务时,系统将调用此方法。一旦执行此方法,服务就会在后台无限期运行。如果你实现此方法,则在服务工作完成后需要通过调用stopSelf()或stopService(Intent intent)来停止服务。如果您只需实现绑定,则无需实现此方法。
- onBand()
当另一个组件通过bindService()与服务绑定时,系统将调用此方法。在此方法的实现中,必须通过返回IBinder提供一个接口,供客户端用来与服务端通信。如果不允许绑定,则返回null。
- onCreate()
首次创建服务时,系统将调用此方法。如果服务已运行,则不用调用此方法。
- onDestory()
当服务被销毁或不再使用时,调用此方法。应实现此方法清理资源。
IntentService:
Service的子类,使用工作线程串行处理多个启动请求,你只需实现onHandleIntent()方法。该方法会接收每一个启动请求的Intent。
IntentService执行的操作:
- 创建工作线程,用于执行执行传递给onStartCommand()的所有Intent。
- 创建工作队列,将Intent逐一传递给onHandleIntent()实现,串行的处理各Intent请求。
- 在处理完所有启动请求后自动停止服务,不用程序员自行处理。
- onBind()默认返回null。
- onStartCommand()方法的默认是实现,将Intent一次发送到工作队列和onHandleIntent()。
public class HelloIntentService extends IntentService {
public HelloIntentService() {
super("HelloIntentService");
}
@Override protected void onHandleIntent(Intent intent) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
继承Service类
使用 IntentService显著简化了启动服务的实现。但是,若要求服务执行多线程(而不是通过工作队列处理启动请求),则可扩展Service类来处理每个 Intent。
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override public void handleMessage(Message msg) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
stopSelf(msg.arg1);
}
}
@Override public void onCreate() {
HandlerThread thread = new
HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
@Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
onStartCommand的返回
onStartCommand必须返回一个整数,代表不同的意义。
- START_NOT_STICKY:如果系统在onStartCommand返回后终止服务,则除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
- START_STICKY:如果系统在 onStartCommand()返回后终止服务,则会重建服务并调用onStartCommand(),但不会重新传递最后一个 Intent。相反,除非有挂起 Intent 要启动服务(在这种情况下,将传递这些 Intent ),否则系统会通过空 Intent 调用onStartCommand()。这适用于不执行命令、但无限期运行并等待作业的媒体播放器(或类似服务)。
- START_REDELIVER_INTENT:如果系统在 onStartCommand()返回后终止服务,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。任何挂起 Intent 均依次传递。这适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
启动Service
- 自从Lollipop以后,只能显示启动Service。
- 如果需要在5.0以上是设备上实现隐式启动,需要使用以下方式。给Intent设置包名。
Intent mIntent = new Intent();
mIntent.setAction("XXX.XXX.XXX");//你定义的service的action
mIntent.setPackage(getPackageName());//这里你需要设置你应用的包名
context.startService(mIntent);
startService()方法将立即返回,且 Android 系统调用服务的 onStartCommand()方法。如果服务尚未运行,则系统会先调用 onCreate(),然后再调用onStartCommand()。
前台运行服务
前台服务被认为是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止** 前台服务必须为状态栏提供通知
**,放在“正在进行”标题下方,这意味着除非服务停止或从前台移除,否则不能清除通知。
要请求让服务运行于前台,请调用 startForeground()。
具体使用方法请查阅相关资料!
绑定服务
基础知识
要提供绑定服务,必须实现onBind()回调方法。该方法返回的IBinder对象定义了客户端与服务进行交互的编程接口。
客户端通过bindService()绑定到服务,调用时必须提供ServiceConnection的实现,来监控与服务的连接。bindService()方法会立即无值返回,但当 Android 系统创建客户端与服务之间的连接时,会对ServiceConnection调用onServiceConnected(),向客户端传递用来与服务通信的IBinder。
多个客户端可同时连接到一个服务。不过,只有在第一个客户端绑定时,系统才会调用服务的onBind()方法来检索IBinder。系统随后无需再次调用onBind(),便可将同一IBinder传递至任何其他绑定的客户端。
当最后一个客户端取消与服务的绑定时,系统会将服务销毁(除非startService()也启动了该服务)。
创建绑定服务
创建提供绑定的服务时,您必须提供IBinder,用以提供客户端用来与服务进行交互的编程接口。 您可以通过三种方法定义接口:
- 扩展Binder类
- 使用Messenger
- 使用AIDL
扩展Binder类
- 在您的服务中,创建一个可满足下列任一要求的Binder实例:
1.包含客户端可调用的公共方法
2.返回当前Service实例,其中包含客户端可调用的公共方法
3.返回由服务承载的其他类的实例,其中包含客户端可调用的公共方法
public class LocalService extends Service {
//返回给客户端的Binder
private final IBinder mBinder = new LocalBinder();
private final Random mGenerator = new Random();
//继承Binder类
public class LocalBinder extends Binder {
//通过该方法取得service实例,以便客户端能够拿到service实例,使用service中的方法
LocalService getService() {
return LocalService.this;
}
}
@Override public IBinder onBind(Intent intent) {
return mBinder;
}
//暴露给客户端的函数
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BindingActivity extends Activity {
LocalService mService;
//标志位,判断客户端是否已经绑定服务。
boolean mBound = false;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override protected void onStart() {
super.onStart();
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;
}
}
public void onButtonClick(View v) {
if (mBound) {
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " +
num,Toast.LENGTH_SHORT).show();
}
}
//ServiceConnection实例,用来监控客户端和Service的连接
private ServiceConnection mConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName className, IBinder service) {
//建立连接时,通过Service传来的IBinder实例得到相应的具体Binder类
LocalBinder binder = (LocalBinder) service;
//通过Binder得到service实例,用该实例使用service中对外开放的方法。
mService = binder.getService();
mBound = true;
}
@Override public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
使用Messenger
如需让服务与远程进程通信,则可使用Messenger为您的服务提供接口。利用此方法,您无需使用 AIDL 便可执行进程间通信 (IPC)。
Messenger方法概要
- 服务实现一个Handler,用来接收来自客户端的每一个回调。
- Handler用于创建Messenger对象
- Messenger创建一个IBinder,服务通过onBinde()返回客户端。
- 客户端使用IBinder将Messenger实例化,然后使用Messenger将Message发送给服务
- 服务在其Handler中处理每一个Message
一个messenger服务
public class MessengerService extends Service {
static final int MSG_SAY_HELLO = 1;
//处理客户端发来的message
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);
}
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
@Override public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
//通过messenger返回Binder
return mMessenger.getBinder();
}
}
客户端根据service返回的Binder创建一个Messenger
public class ActivityMessenger extends Activity {
Messenger mService = null;
boolean mBound;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
//通过service返回的IBinder创建一个Messenger
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className){
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);
setContentView(R.layout.main);
}
@Override protected void onStart() {
super.onStart();
bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
}
@Override protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}