概述
- Service是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件。
- 服务可由其他应用组件启动,且即使用户切换到其他应用,服务仍将在后台继续运行。
- 组件可绑定到服务,以与之进行交互,甚至是执行进程间通信(IPC)。
- 服务可处理网路事务、播放音乐、执行文件IO或与内容提供程序交互。
Service类
要创建服务,必须创建Service的子类或使用它的一个现有子类。
-
声明服务
<manifest ... > ... <application ... > <service android:name="服务的包类名" android:exported="false" /> ... </application> </manifest>
-
重写生命周期的回调方法
- onCreate()
- 何时:首次创建服务时。
- 注意:若服务已在运行,则不会调用此方法。
- onDestroy()
- 何时:当服务不再使用且将被销毁时。
- 作用:清理所有资源,如线程、注册的侦听器、接收器等。
- 注意:这是服务接收的最后一个调用。
- int onStartCommand(Intent intent, int flags, int startId)
- 何时:当另一个组件调用
startService()
请求启动服务时。 - 参数:
- intent:
startService()
启动服务时传入的Intent; - startId:唯一id标识此次服务的启动请求。
- intent:
- 返回值:描述系统应该如何在服务终止的情况下继续运行服务。
- 何时:当另一个组件调用
- IBinder onBind(Intent it)
- 何时:当另一个组件调用
bindService()
与服务绑定时。 - 返回值:供客户端与服务进行通信。
- 何时:当另一个组件调用
- onCreate()
-
服务的销毁
- 调用
startService()
启动服务,则服务将一直运行,直到其自身使用stopSelf()
或由其他组件调用stopService()
来停止。 - 调用
bindService()
创建并绑定服务,则服务只会在该组件与其绑定时运行。一旦该服务与所有客户端之间的绑定全部取消,系统会销毁它。 - 同时被启动和绑定的服务,要经历上面两种才能被销毁。
- 仅当内存过低且必须回收系统资源以供具有用户焦点的Activity使用时,系统才会强制停止服务(前台运行的服务除外)。
- 调用
-
onStartCommand()
的返回值-
START_NOT_STICKY
- 默认情况下,系统不会重新创建服务。除非有将要传递来的Intent时,系统重新创建服务,并调用
onStartCommand()
,传入此Intent。 - 这是最安全的选项,可以避免在不必要的时候运行服务。
- 默认情况下,系统不会重新创建服务。除非有将要传递来的Intent时,系统重新创建服务,并调用
-
START_STICKY
- 系统重新创建服务,并调用
onStartCommand()
,默认是传入空Intent。除非存在将要传递来的Intent,那么就传递这些Intent。 - 适合播放器一类的服务。独立运行,但无需执行命令,只等待任务。
- 系统重新创建服务,并调用
-
START_REDELIVER_INTENT
- 系统重新创建服务,并调用
onStartCommand()
,传入上次传递给服务执行过的Intent。 - 适合像下载一样的服务。立即恢复,积极执行。
- 系统重新创建服务,并调用
-
启动服务
创建启动服务
1. 扩展Service类
与APP同进程的服务是运行在主线程中,不可作耗时操作,但可以创建子线程来完成耗时操作。
创建Service的子类,重写
onCreate()
、onStartCommand()
、onDestroy()
等方法。
2. 扩展IntentService类
-
IntentService执行以下操作:
- 创建工作子线程,用于执行传递给
onStartCommand()
的所有Intent; - 创建工作队列,用于将Intent一个个传递给
onHandleIntent()
处理; - 在处理完所有启动请求后停止服务。
- 提供
onBind()
的默认实现,返回null; - 提供
onStartCommand()
的默认实现,将Intent发送到工作队列。
- 创建工作子线程,用于执行传递给
创建IntentService的子类,只需要一个构造函数和重写
onHandleIntent()
即可。若重写其他方法,要确保调用超类实现,因为IntentService有自己的工作线程生命周期。
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId );
}
}
启动服务
-
startService(Intent it)
启动服务。
Intent intent = new Intent(this, HelloService.class);
startService(intent);
停止服务
- 服务必须通过调用
stopSelf()
自行停止运行,或者由另一个组件通过调用stopService()
来停止它。
绑定服务
创建Service的子类,必须重写
onBind()
以返回IBinder,这个对象定义了组件与服务之间交互的编程接口。-
组件可通过调用
bindService(Intent service, ServiceConnection conn, int flags)
绑定到服务。- 参数service:能标识要绑定服务;
- 参数conn:监控服务的连接和断开;
- 服务连接时,会回调conn的
void onServiceConnected(ComponentName name, IBinder service)
。 -
服务因crash或killed而断开时,会回调conn的
void onServiceDisconnected(ComponentName name)
。
- 服务连接时,会回调conn的
- 参数flags:绑定操作标识。可选有
0, BIND_AUTO_CREATE, BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND,BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, BIND_WAIVE_PRIORITY
。
组件可通过调用
unbindService(ServiceConnection conn)
解绑。多个应用组件可以同时绑定同一个服务。不过,只有在第一个组件绑定时,系统才会调用服务的
onBind()
方法来创建IBinder。当最后一个客户端取消与服务的绑定时,系统会将服务销毁(除非
startService()
也启动了该服务)。
IBinder接口实现
- 绑定服务提供给客户端组件,用来组件与服务进行交互的编程接口。
1.扩展IBinder类
若你的服务仅供本地APP使用,不需要跨进程,则可实现自有Binder类,让你的客户端通过该类直接访问服务中的公共方法。
这个实现方案只有在客户端和服务位于同一个APP同一个进程内才有效。
-
设置方法
- 在服务类中,创建Binder实例,要满足以下任一要求:
- 包含客户端可调用的公共方法;
- 返回当前服务实例,该服务要包含客户端可调用的公共方法;
- 返回由服务承载的其他类的实例,该实例要包含客户端可调用的公共方法。
- 在服务的
onBind()
回调方法中返回此Binder实例。 - 在客户端中,从
onServiceConnected()
回调方法中接收Binder,并使用其提供的公共方法操作服务。
- 在服务类中,创建Binder实例,要满足以下任一要求:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
2.使用Messenger
- 如需让服务与远程进程通信,则可使用Messenger。
- 服务类中实现一个Handler,由其接收来自客户端的每个调用的回调;
- 创建Messenger对象时需传入Handler;
- 在
onBind()
时返回Messenger对象.getBinder()
给客户端; - 客户端在
onServiceConnected()
中接收到IBinder,并将其强制类型转换为Messenger对象。调用Messenger的send(Message msg)
来给服务发送消息; - 服务类中的Handler的
handleMessage()
接收客户端发来的消息。
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
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);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
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();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
3.使用AIDL
- 参考AILD笔记
绑定与解绑服务
-
流程简述
- 客户端实现ServiceConnection
- 重写
onServiceConnected()
- 重写
onServiceDisconnected()
- 客户端调用
bindService()
绑定服务
- 重写
- 与服务连接时,系统会回调
onServiceConnected
,要保存IBinder对象,并使用其调用服务。 - 客户端调用
unbindService()
解绑服务。注意,此时不会回调onServiceDisconnected()
,这个方法只会在服务crash或killed才会被回调。
- 客户端实现ServiceConnection
-
何时绑定与何时解绑
- 若只需要在Activity可见时与服务交互,则应在
onStart()
期间绑定,在onStop()
期间解绑。 - 若希望Activity在后台停止运行时仍可接收响应,则在
onCreate()
期间绑定,在onDestroy()
期间解绑。 - 切勿在
onResume()
期间绑定和onPause()
期间解绑,这是因为每一次生命周期转换都会发生这些回调,频率过高。
- 若只需要在Activity可见时与服务交互,则应在
绑定服务的生命周期
- 绑定服务的回调方法解析
- IBinder onBind(Intent intent);
- 参数intent:来自客户端组件的
bindService()
。 - 返回值:提供给客户端访问服务的公共方法。
- 何时被系统调用:服务被首次绑定,且
onUnbind()
返回false。
- 参数intent:来自客户端组件的
- boolean onUnbind(Intent intent);
- 参数intent:来自客户端组件的
bindService()
。 - 返回值:返回true表明当之后被新客户端绑定时,不调用
onBind()
,而是调用onRebind()
。 - 何时被系统调用:当所有客户端都解绑时。
- 参数intent:来自客户端组件的
- void onRebind(Intent intent);
- 参数intent:来自客户端组件的
bindService()
。 - 何时被系统调用:经历过所有客户端解绑,且
onUnbind()
返回true之后,有新的客户端绑定。
- 参数intent:来自客户端组件的
- IBinder onBind(Intent intent);
前台服务
服务一般都是运行在后台,系统优先级比较低,当系统内存不足时,很有可能被回收掉。而前台服务被认为是用户主动意识到的一种服务,因此即使内存不足,系统也不会考虑将其终止。
前台服务必须为状态栏提供通知,也就是说除非服务停止或从前台删除,否则不能清除通知。
-
Service类的
void startForeground(int id, Notification notification)
可让服务运行于前台。- 参数id:通知的唯一标识,不可为0;
- 参数notification:在状态栏上显示,表明这是前台服务的通知。
Service类的
void stopForeground(boolean removeNotification)
可停止前台服务,布尔值参数指示是否删除状态栏的通知。注意此方法不会停止普通服务,只是针对前台服务。
服务的生命周期
- 启动服务
- 一个组件调用
startService()
启动服务,服务不存在则会创建且onCreate()
被系统调用; -
onStartCommand()
被系统调用; - 这种服务可无限地运行下去,必须自己调用
stopSelf()
或调用stopService()
来停止它,onDestroy()
被系统调用。
- 一个组件调用
- 绑定服务
- 一个组件调用
bindService()
绑定服务,服务不存在则会创建且onCreate()
被系统调用; -
onBind()
被系统调用,并返回IBinder,提供给组件与服务进行通信; - 组件调用
onbindService()
来解绑。多个组件可绑定到同一服务,当所有解绑后,其onUnbind()
被调用,之后系统会销毁它且调用其onDestroy()
。
- 一个组件调用
- 混合服务
- 以上两条路径并非完全独立。服务可被启动和被绑定,这种混合服务只有在所有组件解绑,且自身调用
stopSelf()
或调用stopService()
才会停止运行。
- 以上两条路径并非完全独立。服务可被启动和被绑定,这种混合服务只有在所有组件解绑,且自身调用