服务
在该文献
基础
声明在清单服务
创建一个启动的服务
扩展IntentService类
扩展服务类
启动服务
停止服务
创建绑定服务
将通知发送给用户
运行在前台服务
管理服务生命周期
实施生命周期回调
重点班
服务
IntentService
样本
服务启动参数
本地服务
也可以看看
绑定服务
服务是可以在后台执行长时间运行操作,并且不提供用户界面的应用组件。另一个应用程序组件可以启动服务,它就会继续在即使用户切换到另一个应用程序在后台运行。此外,一个组件可以绑定到一个服务来与它进行交互,甚至进行进程间通信(IPC)。例如,服务可能处理网络交易,播放音乐,执行文件I / O,或与内容供应商进行互动,所有从背景。
服务基本上可以采取两种形式:
入门
服务是“开始”的时候应用程序组件(如活动),通过调用startService启动它()。一旦开始,一个服务可以无限期在后台运行,即使启动它的成分被破坏。通常,启动服务执行单次操作和结果不返回给调用者。例如,它可能下载或上传在网络上的文件。当操作完成时,服务应该停止本身。
界
服务是“必然”时,应用程序组件调用bindService绑定到它()。绑定的服务提供了一个客户端 - 服务器接口,允许组件与服务交互,发送请求,得到的结果,甚至跨越与进程间通信(IPC)的进程这样做。绑定的服务只只要其他应用程序组件绑定到它运行。多个组件可以绑定到服务一次,但是,当它们全部取消绑定,服务被破坏。
虽然此文件通常分别讨论这两种类型的服务,您的服务可以两种方式工作,它可以启动(无限期运行),也允许绑定。它只是你是否实现了几个回调方法的问题:onStartCommand(),以允许组件启动和onBind()允许绑定。
无论应用程序是否是启动的,结合的,或两者的任何应用程序组件可以使用的服务(甚至从一个单独的应用程序),以同样的方式,任何组件可以由活性与意图启动它使用。但是,你可以声明服务为私有,在清单文件,并阻止来自其他应用程序的访问。这是在大约在清单中声明该服务的部分更多的讨论。
注意:服务在其宿主进程,该服务不会创建自己的线程的主线程中运行,在单独的进程不运行(除非另行指定)。这意味着,如果你的服务是打算做任何CPU密集型工作或阻塞操作(如MP3播放或网络),你应该在服务中创建一个新的线程来完成这项工作。通过使用一个单独的线程,你会降低应用风险不响应(ANR)错误和应用程序的主线程可以继续致力于用户交互与你的活动。
基础
如果您使用服务或线程?
服务仅仅是可以在后台,即使用户不与应用程序交互运行的组件。因此,你应该创建一个服务只如果那是你所需要的。
如果你需要你的主线程之外执行的工作,但只有在用户与应用程序交互,那么你或许应该,而不是创建一个新的线程,而不是服务。例如,如果你要玩一些音乐,但你的活动正在运行仅在,你也许可以在一个的onCreate线程(),开始在onStart()运行它,然后停止它的onStop()。也可以考虑使用,而不是传统的Thread类的AsyncTask或HandlerThread。请参阅有关线程的详细信息的过程和线程的文件。
请记住,如果你使用一个服务,它仍然在默认情况下,您的应用程序的主线程中运行,所以你还是应该在服务中创建一个新的线程,如果它执行密集或阻塞操作。
要创建一个服务,你必须创建服务的一个子类(或者其现有的一个子类)。在您的实现,你需要重写处理服务生命周期的关键方面的一些回调方法,并提供了一种机制,组件,如果合适的话绑定到服务。你应该重写最重要的回调方法是:
onStartCommand()
系统调用此方法时另一组件,如一个活动,要求该服务被启动,通过调用startService()。一旦这个方法执行,该服务已启动,可以在后台运行下去。如果实现这一点,这是你的责任,当其工作完成后,通过调用stopSelf()或stopService()停止服务。 (如果你只希望提供绑定,你并不需要实现这个方法。)
onBind()
该系统调用此方法时,另一部分要与服务(如执行RPC)绑定,通过调用bindService()。在实现此方法,您必须提供客户端使用通过返回一个IBinder与服务进行通信,接口。你必须始终实现此方法,但如果你不想让绑定,那么你应该返回null。
onCreate()
该系统调用时,第一次创建服务这种方法,进行一次性设置程序(它调用要么onStartCommand()或onBind()之前)。如果该服务已在运行,这种方法不会被调用。
onDestroy()
系统调用当服务不再使用而被销毁此方法。您的服务应实现此清理任何资源如线程,注册的监听器,接收器等,这是服务接收最后一次通话。
如果一个组件通过调用startService()启动服务(这会导致以onStartCommand()的调用),则该服务一直运行,直到它停止本身stopSelf()或其他部件致电stopService停止它()。
如果一个组件调用bindService()创建的服务(和onStartCommand()不被调用),则服务仅只要该组件绑定到运行。一旦服务是所有客户端绑定,系统破坏它。
只有当内存不足的Android系统将强制停止服务,它必须恢复系统资源为具有用户焦点的活动。如果该服务被绑定到用户具有焦点的活动,那么它不太可能被杀害,而如果该服务被宣布为在前台运行(稍后讨论),那么它几乎不会被杀死。否则,如果该服务已启动,并且是长期运行的,那么系统会降低其在后台任务列表中的位置随着时间的推移,该服务将变得非常容易杀死,如果您的服务已启动,则必须将其设计为优雅地处理由系统重新启动。如果系统杀死你的服务,请尽快重新启动它的资源再次可用(尽管这也取决于你从onStartCommand(返回值),如稍后讨论)。有关当系统可能会破坏服务的更多信息,请参见进程和线程文件。
在下面的章节中,您将看到如何创建每种类型的服务,以及如何从其他应用程序组件使用它。
声明在清单服务
之类的活动(和其他组件),则必须在应用程序的清单文件中声明的所有服务。
要声明你的服务,添加一个<service>元素作为<application>元素的子项。例如:
<
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
请参阅有关清单声明你的服务的更多信息<service>元素引用。
还有其他的属性可以包含在<service>元素来定义属性,如启动该服务,并在服务应该运行过程中所需的权限。 Android的:name属性是唯一必需的属性,它指定服务类的名称。一旦你发布你的应用程序,因为如果你这样做,你断码,由于在明确意图来启动或绑定服务的依赖风险不应该更改这个名字,(阅读博客文章,事情可以不改变)。
为了确保您的应用程序是安全的,启动或结合您的服务时,一定要使用一个明确的意图,并没有为服务声明意图过滤器。如果它的关键,您允许的歧义一定量的该服务启动时,你可以为你的服务供应意图过滤器,并从意图排除组件的名称,但你必须将包与setPackage(),其目的这为目标服务足够消歧。
此外,还可以确保您的服务只提供给您的应用程序由包括Android:exported属性并将其设置为“假”。这有效地启动你的服务,使用一个明确的意图,即使停止其他应用程序。
创建一个启动的服务
已启动的服务是一个另一个组件开始通过调用startService(),造成该服务的onStartCommand()方法的调用。
当服务启动时,它有一个生命周期的自主启动它,服务可以在后台运行无限期组件,即使启动它的成分被破坏。这样,服务应该停止本身时,其作业是通过调用stopSelf(完成),或其他部件可以通过调用stopService停止()。
一个应用程序组件,如一个活性可以通过调用startService启动服务()并传递用于指定的服务,包括用于向使用该服务的任何数据的意图。该服务接收的onStartCommand()方法,这个意图。
例如,假设一个活动需要一些数据保存到一个在线数据库。活动可以启动一个同伴服务,并提供其数据传递的意图,startService保存()。服务接收在onStartCommand()的意图,连接到互联网,并执行数据库事务。当交易完成时,服务停止本身和它被破坏。
注意:一个服务运行在相同的工序中声明它的应用程序,该应用程序的主线程,默认情况下。所以,如果你的服务,而用户从同一个应用程序的交互活动进行密集或阻塞操作,该服务将减慢活动的表现。为避免影响应用程序的性能,你应该开始在服务中一个新的线程。
传统上,还有你可以扩展创建一个启动的服务两大类:
服务
这是对于所有服务的基类。当你扩展这个类,它是创建在其中做的所有服务工作的一个新的线程,因为该服务使用你的应用程序的主线程,默认情况下,这可能会减慢你的应用程序正在运行的任何活动的表现是很重要的。
IntentService
这是服务的子类,使用工作线程来处理所有的开始请求,一次一个。这是最好的选择,如果你不要求你的服务同时处理多个请求。所有你需要做的是落实onHandleIntent(),它接收的每个请求的开始,所以你可以做后台工作的意图。
以下各节描述了如何使用任何一个这些类实现您服务。
扩展IntentService类
由于大多数启动的服务并不需要同时处理多个请求(这实际上是一个危险的多线程情况下),如果你使用IntentService类来实现你的服务很可能是最好的。
该IntentService执行以下操作:
创建一个默认的工作线程执行交付给onStartCommand所有意图()从应用程序的主线程中分离出来。
创建一个在同一时间到你onHandleIntent()实现通1意图,所以你永远不必担心多线程工作队列。
毕竟停止服务启动请求已经被处理,所以你从来没有打电话给stopSelf()。
提供onBind(缺省实现)的返回null。
提供了发送意图的工作队列,然后到你的onHandleIntent()实现onStartCommand()的默认实现。
这一切都增加了一个事实,即所有你需要做的就是实现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) {
}
}
}
}
}
这就是你需要:一个构造函数和onHandleIntent的实现()。
如果您决定还覆盖其他回调方法,如OnCreate()中,onStartCommand(),或的onDestroy()时,一定要调用父类的实现,使IntentService能妥善处理工作线程的使用寿命。
例如,onStartCommand()必须返回默认的实现(这是意图如何被传递到onHandleIntent()):
@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);
}
除了onHandleIntent(),从中你不需要调用超类的唯一方法是onBind()(但你只需要实现,如果你的服务允许绑定)。
在下一节中,您将看到如何扩展基本服务类,这是很多更多的代码,当同类服务的实现,但如果你需要同时处理开始请求这可能是合适的。
扩展服务类
当你在上一节中所看到的,使用IntentService让您一开始服务的实现非常简单。但是,如果你需要你的服务来执行多线程(而不是通过工作队列处理开始请求),那么你可以扩展服务类来处理每一个意图。
为了进行比较,以下示例代码是执行完全相同的工作与上述使用IntentService的例子中的服务类的实现。也就是说,对于每一个启动请求时,它使用一个工作线程来执行该作业和过程在一个时间只有一个请求。
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// 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) {
}
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
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();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
正如你所看到的,它比使用IntentService很多工作。
但是,因为你处理每个调用onStartCommand()你自己,你可以同时执行多个请求。这不是这个例子做什么,但如果这是你想要的,那么你可以为每个请求创建一个新的线程和运行它们的时候了(而不是等待前一个请求完成)。
请注意,onStartCommand()方法必须返回一个整数。整数是描述系统应如何继续在该系统杀死它时服务(如上面所讨论的,IntentService默认实现为您处理此,尽管你可以修改它)的值。从onStartCommand()的返回值必须是以下常量之一:
START_NOT_STICKY
如果系统杀死onStartCommand()返回后,在服务,不重新创建的服务,除非存在未处理的意图来提供。这是为了避免运行服务时,没有必要的,当你的应用程序可以简单地重新启动任何未完成的作业最安全的选择。
START_STICKY
如果系统杀死onStartCommand后服务()返回,重新创建服务和呼叫onStartCommand(),但不重新提交最后意图。相反,系统调用onStartCommand()用空的意图,除非有未决的意图来启动服务,在这种情况下,那些意图传递。这是适合于不执行命令,但无限期运行和等待作业媒体播放器(或类似的服务)。
START_REDELIVER_INTENT
如果系统杀死onStartCommand后,在服务()返回,重新创建服务并调用onStartCommand()与被输送到该服务的最后意图。任何挂起的意图被依次传递。这是适合于正在积极执行该应立即工作恢复时,如下载文件的服务。
有关这些返回值的更多详细信息,请参阅各不变链接参考文档。
启动服务
你可以通过一个Intent(指定服务启动),以startService开始从一个活动或其它应用程序组件服务()。 Android系统调用服务的onStartCommand()方法,并传递给它的意图。 (你永远不应该直接调用onStartCommand()。)
例如,一个活动可以使用带startService()显式意图启动在上一节(HelloSevice)在实施例的服务:
Intent intent = new Intent(this, HelloService.class);
startService(intent);
该startService()方法立即返回,Android系统调用服务的onStartCommand()方法。如果该服务尚未运行,系统首先调用的onCreate(),然后调用onStartCommand()。
如果服务不还提供了绑定,与startService()发表的意图是应用程序组件和服务之间的通信的唯一方式。不过,如果你希望服务的结果发回,然后启动该服务的客户端可以创建一个广播一的PendingIntent(带getBroadcast()),它在启动该服务的意图传递给服务。然后该服务可以使用广播来提供一个结果。
多个请求启动该服务,导致多个相应的调用该服务的onStartCommand()。但是,只有一个要求停止服务(与stopSelf()或stopService())来阻止它。
停止服务
已启动的服务必须管理自己的生命周期。也就是说,该系统不停止或破坏该服务,除非它必须恢复系统内存和服务继续onStartCommand()返回之后运行。因此,该服务必须通过调用stopSelf()停止自身或其他部件可以通过调用stopService停止它()。
一旦请求停止与stopSelf()或stopService()时,系统立即破坏服务成为可能。
但是,如果你的服务处理多个请求onStartCommand()兼任,那么你不应该因为收到一个新的开始请求(在第一年底停止停止服务,当你处理完一个开始请求,因为你可能有请求将终止,第二个)。为了避免这个问题,你可以使用stopSelf(INT),以确保您的要求停止该服务总是基于最新的启动请求。也就是说,当你调用stopSelf(INT),您通过启动请求的ID(该startId交付给onStartCommand())到您的停止请求对应。如果服务接收到一个新的开始要求你能够调用stopSelf(INT)之前,则该ID将不匹配,该服务将不会停止。
注意:重要的是,您的应用程序停止其服务时,它的完成工作,避免浪费系统资源和消耗电池电量。如果有必要,其他部件可以通过调用stopService停止服务()。即使您启用服务绑定,必须始终自行停止该服务,如果它曾经接到一个电话到onStartCommand()。
有关服务的生命周期的更多信息,请参见下面有关管理服务的生命周期。
创建绑定服务
绑定的服务是一个允许应用程序组件通过,以创造一个长期的连接调用bindService()绑定到它(一般不允许组件通过调用startService启动它())。
当你想从活动和其他组件在应用程序或暴露你的一些应用程序的功能到其他应用程序,通过进程间通信(IPC)的服务进行交互,你应该建立一个绑定的服务。
要创建一个绑定服务,必须实现onBind()回调方法返回定义与服务通信的接口一个IBinder。然后,其他应用程序组件可以调用bindService()来检索界面,并开始调用服务方法。该服务只生活服务绑定到它的应用程序组件,因此在没有绑定到的服务组件,系统破坏它(你不需要必须在服务启动时的方式停止绑定服务通过onStartCommand())。
要创建一个绑定的服务,你必须做的第一件事就是定义指定客户端如何与服务通信的接口。服务和客户端之间的接口必须的IBinder的实现,是你的服务必须从onBind()回调方法返回。一旦客户机接收到的IBinder,它可以开始通过该接口的服务进行交互。
多个客户端可以结合到服务于一次。当客户端完成与服务交互,它调用unbindService()来解除绑定。一旦没有绑定到服务的客户端,系统会破坏该服务。
有实现绑定服务多种方式和实现比启动服务的更多复杂,所以绑定服务的讨论出现在有关绑定服务一个单独的文件。
将通知发送给用户
一旦运行,服务可以使用通知通知吐司或状态栏通知事件的用户。
Toast通知是片刻然后消失当前窗口的表面上出现一则消息,而状态栏通知提供了一条消息,用户可以以采取行动选择状态栏(这样的图标作为启动活动)。
通常情况下,一个状态栏通知是最好的技术时,一些后台的工作已经完成(如文件下载完成)和用户现在可以采取行动。当用户选择从展开图的通知时,该通知可以开始一个活动(例如,以查看下载的文件)。
见敬酒通知或状态栏通知开发者指南获取更多信息。
运行在前台服务
前台服务是被认为是东西服务的用户正在积极了解并因此不会对系统杀死时内存不足的候选人。前台服务必须为状态栏,这是摆在“持续”的标题,这意味着该通知不能被解雇,除非该服务停止或从前台删除的通知。
例如,从服务播放音乐的音乐播放器应设置在前台运行,因为用户是明确地知道它的操作。在状态栏中的通知可能表明当前歌曲,并允许用户启动的活动与音乐播放器进行交互。
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
要从前台服务,请致电stopForeground()。此方法需要一个布尔值,指示是否可以取消状态栏通知为好。此方法不停止服务。但是,如果你停止服务,而它仍然在前台运行,则该通知也将被删除。
有关通知的详细信息,请参阅创建状态栏通知。
管理服务生命周期
服务的生命周期比一个活动要简单得多。然而,它更重要的是你要密切关注如何您的服务创建和销毁,因为服务可以在用户不知道的后台运行。
服务生命周期 - 从当它创建时,它的破坏,可以遵循两条不同的路径:
已启动的服务
当另一个组件调用startService()被创建的服务。然后服务将无限期运行,必须通过调用stopSelf自行停止()。另一个组件还可以通过调用stopService停止服务()。如果该服务停止,系统破坏它..
绑定的服务
当另一个组件(客户端)调用bindService()被创建的服务。然后,客户端通过一个IBinder接口服务进行通信。客户端可以关闭致电unbindService连接()。多个客户端可以结合到相同的服务,当它们全部取消绑定,则系统会破坏该服务。 (该服务并不需要自行停止。)
这两条路径都没有完全分开。也就是说,可以绑定到一个已经开始与startService服务()。例如,一个背景音乐服务可以通过与标识所述音乐播放的意图调用startService()开始。以后,可能当用户想要实行一些控制播放器或获取有关当前歌曲的信息,一个活动可以通过调用bindService绑定到服务()。在这种情况下,stopService()或stopSelf()实际上并没有停止服务,直到所有客户端解除绑定。
实施生命周期回调
就像一个活动,一个服务具有可以实现监控服务的状态变化,并在适当的时候进行的工作生命周期回调方法。下面的骨骼服务演示每个生命周期方法:
public class ExampleService extends Service {
int mStartMode; // indicates how to behave if the service is killed
IBinder mBinder; // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used
@Override
public void onCreate
() {
// The service is being created
}
@Override
public int onStartCommand
(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
@Override
public IBinder onBind
(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
@Override
public boolean onUnbind
(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
@Override
public void onRebind
(Intent intent) {
// A client is binding to the service with bindService()
,
// after onUnbind() has already been called
}
@Override
public void onDestroy
() {
// The service is no longer used and is being destroyed
}
}
注:与活动生命周期回调方法,你是不是需要调用父类执行这些回调方法。
图2.服务生命周期。左边的图显示()时,服务与startService创建的生命周期和右边的图显示了生命周期时bindService创建服务()。
通过实施这些方法,你可以监视服务生命周期的两个嵌套循环:
服务的整个生命周期中发生的onCreate()被调用的时候,时间的onDestroy()返回间。就像一个活动,服务确实在OnCreate()中的初始设置并释放所有的onDestroy剩余资源()。例如,音乐播放服务可以创造一个音乐将在OnCreate()中播放线程,然后停止的onDestroy线程()。
在OnCreate()中和的onDestroy()方法调用所有服务,无论他们是由startService()或bindService()创建的。
一个服务的活性寿命开始到呼叫或者onStartCommand()或onBind()。每种方法分别移交)传递给任何startService()或bindService(意图,。