Android官方文档-Services(服务)
来源:互联网 发布:月球背面的秘密知乎 编辑:程序博客网 时间:2024/05/19 10:13
一个Service
是应用程序的一个组件,可以在后台执行长时间运行操作,并且不提供用户界面。另一个应用程序组件可以启动一个服务,即使用户切换到另一个应用程序后它也继续在后台运行。此外,一个组件可以绑定到一个服务上与其交互,甚至进行进程间通信(IPC)。例如,一个服务可以处理网络交易,播放音乐,执行文件流I / O,或与内容提供者进行交互,所有这些都在后台执行操作。
服务基本上可以采取两种形式:
- 开始(Started)
- 当应用程序组件(如activity)通过调用
startService()
启动服务时,服务被启动。一旦启动,服务可以在后台运行下去,即使启动它的组成部分被销毁。通常,已启动服务执行单一操作并且其结果不会返回给调用者。例如,它可能通过网络下载或上传的文件。当操作完成时,服务应停止本身。 - 绑定(Bound)
- 当应用程序组件通过调用
bindService()
绑定到服务。绑定服务提供一个客户端-服务器接口,允许组件与服务交互,发送请求,获得返回结果,即使通过IPC这样做。绑定服务和另一个与之绑定的组件运行时间一样长。多个组件可以同时绑定到同一个服务,但是当它们全部取消绑定时,服务会被销毁。
虽然本文分别讨论了这两种类型的服务,但是你的服务可以同时以这两种方式工作,它可以被启动(无限期运行),也允许绑定。这只是你是否实现了几个回调方法的问题:onStartCommand()
以允许组件启动,onBind()
允许绑定。
不管是否应用程序被启动,被绑定,或两者兼而有之,任何应用程序组件可以使用服务(甚至来自于一个单独的应用程序),同样,任何组件可以使用activity—用一个Intent来启动它。但是在清单文件中,你可以将服务声明为私有的,并阻止来自其他应用程序的访问。有关这点的更多讨论请参阅Declaring the service in the manifest。
注意:服务运行在其宿主进程的主线程—服务不会创建自己的线程,也不会运行在一个独立的进程中(除非另行指定)。这意味着,如果你的服务打算做任何CPU耗时操作或异步操作(如MP3播放或网络),你应该创建一个新的线程来执行这类操作。这样就减少了应用程序异常的风险,主线程就可以专门负责和你的activity交互。
基础知识
您使用服务还是线程?
服务仅仅是可以在后台运行的组件,即使用户不与应用程序交互。因此,如果你需要,你应该创建一个服务。
如果你需要在你的主线程之外执行操作,但只有在用户与应用程序交互时,那么你或许应该改为创建一个新的线程,而不是一种服务。例如,如果你要播放一些音乐,但仅当您的activity正在运行时,你可以在onCreate()
中创建一个线程,在OnStart()
时运行它,然后在onStop()
时停止它。也可以考虑使用AsyncTask
或HandlerThread
代替传统的Thread类。关于更多的线程信息请参阅Processes and Threading文档。
请记住,如果你使用服务,而在默认情况下它仍然运行在应用程序主线程中,如果它执行CPU耗时操作或异步操作,那么你还是应该在服务中创建一个新的线程。
要创建一个服务,你必须创建Service的子类(或者其现有的一个子类)。在您的实现中,你需要重写处理服务生命周期关键方面的一些回调方法,并为组件绑定到服务上提供一个机制,如果合适的话。最重要的回调方法,你应该重写的如下:
onStartCommand()
- 当另一组件,如一个activity,通过调用
startService()
要求该服务被启动时,系统调用此方法,一旦这个方法执行,该服务被启动,并且可以在后台运行下去。如果实现这一点,那么当它的工作完成以后,你有责任通过调用stopSelf()
orstopService()
来停止服务(如果你只希望提供绑定,您不需要实现此方法。) onBind()
- 当其他组件要绑定到服务(如执行RPC),通过调用
bindService(),
系统会调用这个方法。在实现此方法时,通过返回一个IBinder,
你必须提供客户端与服务进行通信的接口。你必须始终实现此方法,但如果你不想让绑定,那么你应该返回null。 onCreate()
- 当服务第一次被创建时,系统会调用此方法,目的是一次性执行该过程(在调用
onStartCommand()
或onBind()方法前)。如果服务已经运行,此方法就不会被调用。 onDestroy()
- 当服务不再被使用,并被销毁时,系统调用这个方法。您的服务都应实现此方法,用来清理资源,如线程,注册的监听器,接收器等,这是服务接收的最后一次调用。
如果一个组件通过调用startService()启动服务(其导致调用onStartCommand()
),则服务保持运行,直到它用stopSelf()停止本身或另一组件通过调用stopService()停止它。
如果一个组件调用 bindService()
来创建服务(onStartCommand()
不被调用),那么只要这个组件绑定到服务,服务就会一直运行。一旦服务从素有的客户端解绑,系统会销毁它。
Android系统将强行停止服务,在系统内存不足并且必须为有用户焦点的activity恢复系统资源时。如果服务被绑定到了有用户焦点的activity上,那么它不容易被杀死,如果该服务被声明为在前台运行( run in the foreground)(稍后讨论),那么它几乎不会被杀死。否则,如果服务被启动,并且是长期运行的,那么随着时间的推移系统会降低其在后台任务列表中的位置,服务将变得非常容易杀死—如果您的服务被启动,则必须设计它由系统更好的处理重新启动。如果系统杀死你的服务,一旦资源再次可用(尽管这也取决于你从onStartCommand()返回的值,稍后讨论)服务被重新启动。有关系统可能会销毁服务的更多信息,请参见进程和线程 ( Processes and Threading)文档。
在下面的章节中,您将看到如何创建每种类型的服务,以及如何在其他应用程序组件中使用它。
在清单文件中声明服务(Declaring a service in the manifest)
类似的activity(或者其他组件),必须在应用程序的清单文件中声明所有的服务。
要声明你的服务,添加
元素作为<service>
<application>
的子元素。例如:
<manifest ... >
...
<application ... >
<serviceandroid:name=".ExampleService"/>
...
</application>
</manifest>
有关在清单文件中声明你的服务的详细信息请参阅<service>
文档。
还有其他的属性,你可以包括在
元素中,用来定义一些属性,如启动该服务和服务运行在那个进程所需的权限。该<service>
属性是唯一必需的属性,它指定服务的类名。一旦你发布你的应用程序,你不能更改这个名称,因为如果你这样做,你就有可能断码,因为用明确意图来启动或绑定服务依赖于此(阅读博客文章, Things That Cannot Change)。android:name
为确保您的应用程序是安全的,始终使用显示意图来启动或绑定你的服务,并且不需要为服务声明Intent过滤器。如果你允许一定量的模糊性去启动服务,你可以为你的服务提供Intent filters和排除component name的Intent,但同时你也必须为你的Intent用setPackage()设置能够消除歧义的包名。
此外,通过设置
= false属性,还可以确保您的服务仅用于您的应用程序。这有效地阻止其他应用程序启动你的服务,使用一个显示的意图时也是如此。android:exported
创建已启动服务(Create a Started Service)
已启动的服务是另一个组件通过调用startService()
启动的,导致调用该服务的 onStartCommand()
方法。
当服务被启动,它有一个生命周期,这独立于启动它的组件,即使启动它的部件被销毁,服务也可以在后台无限期运行。这样,服务应在其完成工作以后通过调用stopSelf()停止自己,或另一个组件通过调用stopService()停止它。
一个应用程序组件,如一个activity,可以通过调用startService()启动服务并传递一个Intent
,这个Intent指定服务并包含服务需要使用的任何数据。服务在onStartCommand()
方法中接收这个Intent
。
例如,假设一个activity需要保存一些数据到一个网络数据库中。该activity可以启动一个“同伴“服务,先将数据保存到一个Intent对象中,然后再把这个Intent对象当作参数传递给startService()方法。服务在onStartCommand()中接收这个Intent,连接到互联网,并执行数据库事务。当交互完成时,服务停止自己并被销毁。
注意:在默认情况下,Service运行在它所在的应用程序的主线程中,如果您的服务进行密集或阻塞操作,而用户又在跟同一个应用程序交互,那么服务将会降低你的程序的效率。为了避免影响应用程序的性能,你应该在服务内另起一个线程。
传统上,有两个类可以继承到创建启动服务:
Service
- 这是所有服务的基类。继承此类,对于在服务中创建新线程很重要,因为默认服务使用应用程序的主线程,可能会降低程序的性能。
IntentService
- 这是一个Service的子类,这个类使用线程处理所有启动请求,一次一个。这是不适用服务处理多任务请求的最佳选择,你需要做的只实现onHandleIntent()方法即可。可以为每个启动请求接收Intent,并放到后台去执行。
以下各节描述了如何使用任一这两个类实现您服务。
继承IntentService类(Extending the IntentService class)
因为大多数已启动服务并不需要同时处理多个请求(这实际上可能是在一个危险的多线程情况下),如果你使用IntentService
类实现您服务,这可能是最好的选择 。
IntentService
执行以下操作:
- 创建一个独立于应用主线程的默认工作线程,这个线程执行将所有的Intent传递给onStartCommand()。
- 创建一个工作队列,它依次只能传递一个Intent给你实现的onHandleIntent(),所以你永远不必担心多线程。
- 在所有的启动请求都被处理后停止服务,从而你不用调用stopSelf()。
- 提供默认返回null的onBind()实现。
- 提供默认的onStartCommand()实现,它发送意图到工作队列,然后到你的
onHandleIntent()实现
。
所有这一切都增加了一个事实,即所有你需要做的是实现onHandleIntent()
,用来完成客户端提供的工作。(虽然,你还需要提供一个小的构造函数给服务。)
这里有一个IntentService实现的例子:
public class HelloIntentService extends IntentService{
/**
* A constructor is required, and must call the superIntentService(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();
returnsuper.onStartCommand(intent,flags,startId);
}
除了onHandleIntent()
,从中你不需要调用父类唯一的方法就是onBind(),
(如果你的服务允许绑定,你只需要实现)。
在下一节中,您将看到,当继承Service
基类时,同种服务是如何被实现的,这会有很多的代码,但如果你需要同时处理启动请求,这可能是合适的。
继承服务类(Extending the Service class)
正如你在上一节中所看到的,使用IntentService
让你实现一个已启动服务非常简单。但是,如果你需要你的服务来执行(而不是通过工作队列处理启动请求)多线程,那么你可以继承Service
类来处理每一个Intent。
为了进行比较,以下示例代码是一个实现Service
类执行如上面使用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{
publicServiceHandler(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 =newHandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler =newServiceHandler(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
returnnull;
}
@Override
publicvoid onDestroy(){
Toast.makeText(this,"service done",Toast.LENGTH_SHORT).show();
}
}
正如你所看到的,它比使用IntentService工作量大。
但是,在onStartCommand()方法中因为是自己处理每个调用,所以你可以同时执行多个请求。这不是本例中的做法,但如果这是你想要的,那么你可以为每个请求创建一个新的线程,并立刻运行它们(而不是等待前一个请求完成)。
请注意,onStartCommand()
方法必须返回一个整数。该整数是一个值,描述系统应该如何继续该服务,在系统杀死该服务后。从而onStartCommand()返回值必须是以下常量之一:
START_NOT_STICKY
- 如果系统在
onStartCommand()
返回后杀死后服务,不重新创建的服务,除非存在未处理的意图来传递。当没有必要和你的应用程序能简单重新启动没有完成的工作时,你想要避免运行你的服务,这是个安全的选择。 START_STICKY
- 如果系统在
onStartCommand()
返回后杀死后服务,重新创建服务并调用onStartCommand()
,但不重新传递的最后一个Intent。相反,系统调用onStartCommand()
,所用的Intent为空,除非有未处理的Intent来启动服务,在这种情况下,那些Intent都被传递。这是适合媒体播放器(或类似的服务)未执行命令,只是无限期运行,等待工作。 START_REDELIVER_INTENT
- 如果系统在
onStartCommand()
返回后杀死后服务,用最后被传递给服务的Intent重新创建服务并调用onStartCommand()
。任何未处理的Intent反过来被传递。这是适合于正在积极执行应该立即恢复的工作的服务,如下载文件的服务。
有关这些返回值的更多详细信息,请参阅相关文档。
启动服务(Starting a Service)
从一个activity或其他应用程序组件,你可以通过传递一个Intent(指定要启动的服务)给
startService()
来启动一个服务。Android系统调用服务的onStartCommand()
方法,将Intent传递给它。(你不应该直接调用onStartCommand()
。)
例如,一个activity就可以启动在上一节中的示例服务(HelloSevice
),传递一个显示意图给startService()
:
Intent intent =newIntent(this,HelloService.class);
startService(intent);
startService()
方法立即返回,Android系统调用服务的onStartCommand()
方法。如果服务尚未运行,系统首先调用onCreate()
,然后调用onStartCommand()
。
如果服务不提供绑定,用startService()传递意图是应用程序组件和服务之间的通信的唯一方式。但是,如果你希望服务发送一个结果回去,然后启动该服务的客户端可以创建一个PendingIntent
的广播(带getBroadcast()
),并将其传递给服务从而启动该服务。然后该服务可以使用广播来传递一个结果。
并发请求启动服务导致并发响应调用onStartCommand()函数,但是唯一停止服务的方法是调用stopSelf()或者stopService()方法。
停止服务(Stopping a Service)
已启动的服务必须管理自己的生命周期。也就是说,系统不会停止或破坏该服务,除非它必须恢复系统内存和服务在onStartCommand()
返回后继续运行。因此,该服务必须通过调用stopSelf()
停止本身或其他组件通过调用stopService()停止服务。
一旦请求用stopSelf()
或stopService()
停止服务时,系统会尽可能的销毁服务。
然而,如果当前你的服务在onStartCommand()中处理多个请求,那么在你正在处理这样的启动请求时,你不应该停止服务,因为你可能接收到一个新的启动请求(在第一个请求的结尾停止服务会终止第二个请求)。为了避免这个问题,你可以使用stopSelf(INT)
,以确保您停止该服务的要求总是基于最新的启动请求。也就是说,当你调用stopSelf(INT)
,你传递启动请求的ID(startId被传递给onStartCommand()
)到对应的停止服务的请求。在你能调用stopSelf(INT)之前,如果服务接收到新的启动请求,则该ID将不匹配,该服务不会停止。
注意:重要的是,当服务完成工作后,以避免浪费系统资源和消耗电池电量,您的应用程序应该停止其服务。如果必要的话,其他组件可以通过调用stopService()停止服务。即使绑定服务,必须始终自己停止该服务,如果它曾经接到一个onStartCommand()调用。
有关服务生命周期的更多信息,请参见下面的有关文档管理服务的生命周期。
创建一个绑定服务(Creating a Bound Service)
绑定服务允许应用程序组件通过调用bindService()
绑定到它,以创造一个长期的连接(通常不允许组件通过调用startService()启动它)。
当你想从应用程序中的activity和其他组件通过进程间通信(IPC)跟服务交互或共享你应用的部分功能给其他应用时,你应该创建一个绑定的服务。
要创建一个绑定服务,必须实现onBind()
回调方法返回一个IBinder
,它定义了与服务通信的接口。那么其他应用程序组件可以调用 bindService()
来检索这些接口,并开始调用该服务的方法。服务存在的时候只服务于跟它绑定的应用程序组件,所以当没有组件绑定到服务,系统会销毁该服务(当通过调用onStartCommand()方法启动一个绑定的服务后,你不必强行关闭它)。
要创建一个绑定的服务,你必须做的第一件事就是定义指定客户端如何与服务通信的接口。服务和客户端之间的这种接口必须是一个IBinder对象
,并且必须从onBind()
回调方法返回。一旦客户端接收到IBinder
对象,就可以开始通过该接口与服务进行交互。
多个客户端可以一次性绑定到服务。当客户端与服务进行交互完成,它调用unbindService()
解除绑定。一旦没有绑定到服务的客户端,系统会销毁该服务。
有多重方式来实现一个绑定服务,并且这些实现方式比启动服务更复杂,所以绑定服务在 Bound Services中单独讨论。
发送通知给用户(Sending Notifications to the User)
一旦运行后,服务可以用Toast Notifications or Status Bar Notifications通知用户一些事件。
Toast通知通常是在当前窗口弹出一个小的信息提示,并且过会就消失。而状态栏通知在状态栏显示一个带有信息的图标,用户可以选择这个图标做一些操作(如启动一个activity)。
一般,当一些后台工作已经完成(如文件完成下载),并且用户可以针对它做一些操作时,状态栏通知是最好的技术。当用户从展开的状态栏视图中选择通知时,该通知可以开始一个activity(例如,查看下载的文件)。
更多信息请参阅 Toast Notifications or Status Bar Notifications 开发者引导文档。
在前台运行服务(Running a Service in the Foreground)
前台服务是一种考虑到系统内存不足,但是用户已经意识到而且又不想关闭的服务。前台服务必须在状态栏做出提示,表示该服务在持续进行中,意思就是这种提示除非服务停止或者从所有的前台服务中被移除才能消失。
例如,用服务操作音乐播放器播放音乐,应该在前台播放,因为用户是明确地指出了它的操作。在状态栏上的通知可指明当前歌曲,并允许用户启动一个activity与音乐播放器进行交互。
要请求您的服务在前台运行,调用startForeground()
。这种方法有两个参数:一个整数,表示提示信息的唯一标识和Notification对象,表示状态栏。例如:
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 );
注意:您给 startForeground()
的整数ID不能为0。
要从前台服务中移除服务,请调用stopForeground()
。此方法需要一个布尔值,表明是否要删除状态栏通知。此方法不会停止服务。但是,如果你停止了服务,而它仍然在前台运行,则该通知也将被删除。
有关通知的详细信息,请参阅 Creating Status Bar Notifications。
管理服务的生命周期(Managing the Lifecycle of a Service)
一个服务的生命周期比一个activity的要简单得多。但是,更重要的是你要密切关注服务是如何被创建和销毁,因为服务可以在不被用户察觉的后台运行。
服务的生命周期 - 什么时候被创建,什么时候被销毁—可以遵循两条不同的方式:
- 已启动的服务
当另一个组件调用startService()时,服务被创建。服务可以无限期运行,必须通过调用
stopSelf()
停止本身。其他组件也可以通过调用stopService()停止服务。如果该服务停止,系统会销毁它.. - 绑定的服务
当其他组件(客户端)调用bindService()时服务被创建。然后,客户端通过
IBinder
接口与服务进行通信。客户端可以 通过调用unbindService()
关闭连接。多个客户端可以绑定到同一个服务上,当它们全部取消绑定,系统会销毁该服务。(该服务不需要自行停止。)
这两中方式是不完全分开的。也就是说,你可以绑定到一个已经通过调用startService()启动的服务。例如,一个背景音乐服务可以通过调用startService()启动,并通过其携带的Intent来指示播放音乐。之后,用户可能执行某些操作或者获取当前歌曲的信息,一个activity通过调用bindService()绑定到某个服务。在这种情况下,直到所有客户端全部取消绑定,stopService()或者stopSelf()方法实际并没有停止服务。
实现生命周期回调(Implemengting the lifecycle callbacks)
就像activity,服务也有声明周期回调方法,这些回调方法可以实现监控服务变化的状态,并在适当的时候执行工作。下面的服务框架演示生命周期的每个方法:
public class ExampleService extendsService{
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 voidonCreate
(){
// The service is being created
}
@Override
public intonStartCommand
(Intent intent,int flags,int startId){
// The service is starting, due to a call tostartService()
return mStartMode;
}
@Override
public IBinderonBind
(Intent intent){
// A client is binding to the service withbindService()
return mBinder;
}
@Override
public booleanonUnbind
(Intent intent){
// All clients have unbound withunbindService()
return mAllowRebind;
}
@Override
public voidonRebind
(Intent intent){
// A client is binding to the service withbindService()
,
// after onUnbind() has already been called
}
@Override
public voidonDestroy
(){
// The service is no longer used and is being destroyed
}
}
注:不同于activity生命周期的回调方法,你不需要调用其父类的回调方法。
图2.服务的生命周期。左边的图显示了当该服务使用startService()被创建时的生命周期,右边的图显示了当服务用bindService()创建服务时的生命周期。
通过实现这些方法,您可以监控服务生命周期的两个嵌套的循环:
- 服务的整个生命周期发生在
onCreate()
被调用和onDestroy()
被销毁之间。类似于activity,服务确实在其中onCreate()
初始化设置,并在onDestroy()中释放所有剩余资源。例如,一个音乐播放服务可以在onCreate()中创建一个线程,然后在onDestroy()中停止线程。onCreate()
和onDestroy()
方法在所有的服务中都会被调用,无论他们是通过startService()或bindService()
创建。 - 服务活动周期开始于
onStartCommand()
或onBind()
被调用。这两个方法是当意图传递给startService()或bindService()才被调用。如果服务已启动,其活动周期和整个生命周期同时结束(即使在onStartCommand()返回后,服务仍处于活动状态)。如果该服务被绑定,在onUnbind()返回后活动周期结束。
注:尽管调用stopSelf()
或stopService()
可以停止服务,但是停止时没有一个相应的回调方法被调用(没有onStop()
回调)。因此,除非服务绑定到客户端,当服务被停止时,系统会销毁它——onDestroy()是它接收到的唯一回调。
图2展示了服务的两种典型的回调方法流程,尽管一个用startService()创建服务,一个用bindService()创建服务,但是请记住,任何服务,不管它是如何启动的,都允许客户端绑定它。所以,一个用onStartCommand()(客户端调用startService())初始化启动的服务仍可以调用onBind()方法(当客户端调用bindService()时)。
关于更多创建提供绑定的服务的详细信息,请参阅相关文档:Bound Services、Managing the Lifecycle of a Bound Service等。
- Android官方文档-Services(服务)
- Android官方文档-Bound Services(绑定服务)
- Android 官方文档 Google Services
- Android官方文档之Services
- Android官方文档之Services
- Android 官方文档 - Bound Services
- 【Android官方文档】翻译Android官方文档-Services(二)
- Android HIDL 官方文档(四)—— 服务与数据转换(Services & Data Transfer)
- Android官方文档之Bound Services
- android services启动方式 官方文档翻译
- android 6.0 官方开发文档翻译 服务
- Services简介,翻译自官方文档
- android Services(服务)
- Android Services(服务)
- Android 服务Services小结
- Android服务Services
- android 官方SDK文档
- android官方文档
- ios-html-get/post的区别,一言以蔽之(MS)CheckST
- gre填空句子分割法解析
- php判断一个值是否在一个数组中,区分大小写-也可以判断是否在键中
- 黑马程序员——java基础2
- Reverse Linked List
- Android官方文档-Services(服务)
- LeetCode 之 Swap Nodes in Pairs — C 实现
- iOS各机型参数对比
- Linux-软连接与硬链接
- 3 way quick sort
- 面试题杂货铺(四)
- Linux下Makefile的编写
- 数据库备份
- viewflip和viewpage