Evernote Export
服务,是一个应用组件,它是一个可以执行长时间后台操作的组件,并且没有UI。应用里的其他组件可以启动服务,然后服务就开始运行,即便用户切换到了其他应用,服务也根本停不下来。另外,某其他组件也可以绑定到一个服务与之交互甚至搞一些进程间通信(interprocess communication——IPC)。比如,服务可以处理网络事务,播放音乐,执行文件I/O,或者和内容提供者进行交互,所有这些都在后台进行。

关于如何让服务运行起来,有两种形式:
启动(started):当另外一个组件(比如活动)通过调用startService()来启动服务的时候,这时候我们就说服务被"started"(启动)。服务一旦被启动起来,就会无限期的运行下去,即使那个启动它的组件(比如上面提到的活动)被销毁,服务也会运行下去。通常来说,被启动的服务会执行一些比较单一的操作并且不会给启动它的组件返回任何东西。比如服务可以通过网络下载或者上传一个文件。当下载/上传完成后,它应该停止运行(怎么停止后面再说)。

绑定(Bound):当另外一个组件(比如活动)调用bindService()时,我们称服务被"Bound(绑定)"了。被绑定的服务提供了一种“客户端/服务器”接口,允许组件和服务进行交互,如发送请求啊,接收结果啊,甚至这些操作都可以跨进程进行(通过IPC)。被绑定的服务只在组件和服务绑定的期间运行,解绑了就不行了。多个组件可以同时绑定到某服务,然后等到这些组件全都和服务解绑之后,服务就会被销毁。

尽管这篇文档将两种方式分开来讨论,但是你用的时候可以一起用——一个服务可以同时被启动和被绑定。问题仅仅在于你有没有实现那几个回调方法:实现了onStartCommand()服务才可以允许被启动,而实现了onBind()的服务允许被绑定到别的组件。

不管是通过启动,还是通过绑定或两个方法都用,任意应用里的组件都可以使某个service运行起来(不管是同应用内还是跨应用),运行方法和启动活动差不多——都是用Intent。不过,你可以在manifest里把服务声明为private,阻止别的应用来访问此服务。

注意:服务默认是运行在它宿主进程的主线程当中的,服务自身不会启动新线程也不会在另外的进程里运行(除非你手动指定)。这样的话,如果你的某服务是要做一些CPU负载较高的工作或者阻塞式操作(比如播放mp3或者连接网络)的话,你应该在服务里手动创建一个新线程。这样做的好处是可以减小出现ANR(Application Not Responing,应用无响应)错误的几率,并且你的主线程依然可以专注于通过活动和用户进行交互,用户体验会比较好。

基础:
想要创建一个新服务,你需要创建一个类继承Service类(或Service的某个子类)。然后需在你的类里面实现一些回调方法,通过这些方法可以处理一些服务生命周期的关键部分,并且这些方法也提供了允许其他组件绑定到服务的机制。最重要的回调函数如下:
onStartCommand()
当其他的组件(如活动)调用startService()来启动服务的时候,系统就会调用服务的onStartCommand()方法。一旦执行完这个方法,服务就可以启动并在后台无限地运行下去了。如果你实现了这个方法,那么如何停止服务就是你的事了,通过调用stopSelf()或stopService()可以停止服务(当然如果你只想让你的服务被绑定,而不要被启动,那就不用实现onStartCommand()方法)。
onBind()
当其他的组件调用bindService()想要绑定到服务的时候,系统会调用服务的onBind()方法。在你对这个方法的实现里,你需要提供一个接口给客户端,让客户端以此来与服务通信,而这个接口就是onBind()方法返回的IBinder对象。这个方法是你必须要实现的,如果你不想让别人绑定到你的服务,那就在方法里return null好了。
onCreate()
服务第一次被创建的时候系统会调onCreate()方法,执行一次性的创建过程(在调用onStartCommand()或onBind()之前)。如果服务已经在运行了,这个方法就不会被调到。
onDestroy()
当某服务不会再被用到而且马上就要被销毁的时候,系统会调用onDestroy()方法。你在实现的这个方法里,应该去析构/释放各种资源,像线程或者注册的监听器或者receiver等等。onDestroy()是服务临死前最后一次被调到了方法。

如果某组件通过调用startService()启动了服务(系统会接着调用服务的onStartCommand()),那么服务便会不停的运行下去,直到服务自己调用stopSelf()或者另一个组件调用stopService()将它停止。

如果某组件通过调用bindService()创建了服务(这下就不会调onStartCommand()了),那么只有该组件还绑定在服务上的期间服务才会运行。一旦服务和所有的客户端都解绑(绑定到服务的组件都叫客户端),系统就会销毁这个服务。

如果系统剩余内存不足,而且需要给用户焦点所在的活动提供必须的资源,这时系统会强制停止某些服务。如果某个服务是被绑定在那个用户焦点活动上的话,它被停止的几率就会小一些,而如果某服务被声明为前台服务(稍后讨论)的话,那它基本就不会被杀掉了。如果服务是被启动起来的而不是绑定,并且是一个长期运行的服务,那系统会随着时间推移而不断降低它在后台任务中的位置(或者说不断降低它的优先级),然后这个服务就会变得很危险随时可能被系统杀掉。那么这种情况下,你就需要通过适当的设计处理这种被杀掉然后重新启动的情况。如果你的服务是被系统杀掉的,那么一旦资源又足够用的时候系统会自动把它重新启动起来(当然这也取决于你在onStartCommand方法中的返回值,稍后讨论)。

接下来,我们来看看如何创建各种服务和如何在其他应用组件中使用服务。

在Manifest中声明服务:
就像活动或者其他组件一样,你需要在你应用的Manifest中声明你的所有服务。在<application>节点下添加<service>子节点即可。如:
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
<service>节点中还有很多你可以添加的属性,比如启动此服务需要的权限还有这个服务运行在哪个进程。android:name属性是唯一的必选项,它指明了服务的类名。应用一旦发布,类名就别改了,因为若有别的组件通过显式intent想要绑定到你的服务的话,你一改名就乱套了。
为了确保你的应用的安全性,启动或者绑定服务的时候一定要使用显式intent,并且不要给服务声明intent filters。
如果你必须要在“启动哪个服务”问题上搞些朦胧的可能性(隐式intent就是这样,给个action然后系统帮你找合适的组件去启动,你给的intent并不会明确指明启动某个具体服务,所以叫模糊或者朦胧ambiguity),那你可以给你的服务声明intent filters,然后在其他地方用intent启动服务的时候,把组件名去掉(就是可以使用隐式intent了)。然而并没有完,你还需要调一下setPackage()方法给隐式intent指定一下(目标服务所在)应用的包名,这样就给该intent的目标服务提供了“不模糊”的限定(disambiguation)。。。
另外,还有个属性叫android:exported,你把它设为false就可以保证你的服务只在应用内部才可以访问。这样可以阻止别的应用来启动你的服务,就算通过显式intent指定类名也不行。

创建一个被启动的服务:
什么叫被启动的服务,就是别的组件通过startService()启动的服务,startService()会让系统调到服务的onStartCommand()方法。
服务一旦被启动,就会拥有一个独立的生命周期(和那个启动它的组件就没关系了)并且可以无限运行下去,就算那个组件被干掉(说过好几遍了?)。这种情况下,服务在完成自己的使命之后应该自己调用stopSelf()自我了断,或者其他组件调用stopService()帮你了断。
某应用下的组件,如活动,可以通过调用startService()且传入一个指明具体服务的intent来启动一个服务,当然那个intent里也可以传一些参数给服务来用。服务会在onStartCommand()方法中作为参数收到你传的intent。
假设某个活动需要想网络上的数据库存点数据,它便可以通过startService()启动一个服务,传入一个intent并在其中加入要存的数据。然后服务会在自己的onStartCommand()中接收到intent,连上网络处理数据库事务,存完之后,自我了断然后被销毁。

注意:默认情况下服务是运行在所属应用的进程里,并且在主线程中运行。所以,如果用户正在和同应用下的某个活动进行交互,而这个服务又要进行一些高负荷或者阻塞式的任务,那这个服务就会影响到用户交互的活动的性能,从而影响到用户体验。为了避免此影响,你应该在服务中启一个新线程(上面好像也说过?)。

一般来说,为了创建服务可以继承下面两个类:
Service:
这个类是所有服务的基类,如果你使用继承此类来启动服务,那一定要记得,服务提供的任何操作都要在子线程里进行,因为上面提到了服务默认是运行在你应用的主线程里的。后面blablabla第三遍了。。。

IntentService:
这个类是Service的一个子类,对所有的请求,这个类会启一个工作线程来依次处理。如果你不需要在服务中并行地处理请求,那这个类就是最佳选择,你要做的事情就是实现onHandleIntent()方法, 方法中会接收到请求者发来的intent,然后你据此来执行后台操作。
接下来就看看如何继承这两个类来实现我们的服务。

继承IntentService类:
考虑到大多数情况下服务都不需要并行地处理请求(这种处理方式其实是会引发很多线程安全性问题的),继承IntentService来实现服务是最好的选择。
IntentService功能如下:
1.在主线程之外启动了一个工作线程来处理所有发给onStartCommand()的intent们。
2.创建了一个工作队列,将intent们依次一个一个传给onHandleIntent()方法,这样你永远不用担心多线程的问题。
3.处理完所有请求之后会自行了断,你不需要调什么stopSelf()方法。
4.默认就实现了onBind()方法(返回null)
5.默认实现了onStartCommand()方法:将所有的intent都发给上面提到的工作队列,然后由队列再发给onHandleIntent()。
同时再考虑到实现这个类你只需要实现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.传入启动这个服务的intent,在工作线程中调用下面这个方法,在适当的时候停止服务
*/

@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) {
}
}
}
}
}
如果你要重写其他的回调函数,像onCreate(),onStartCommand(),onDestroy()什么的,记得要调用父类的方法,以便IntentService适当地处理工作线程。
比如,onStartCommand()一定要返回默认的父类实现(正是在父类实现里把intent给到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默认已经实现了返回null的onBind,如果你希望服务允许被绑定你才需要自己重写,和Service类不一样,在Service里你需要自己实现一个返回null的onBind()方法)。
下一环节,你会看到继承Service的实现,代码会比较多,但是如果你需要并行的处理请求的话用Service类还是比较合适的。

继承Service类:
通过上一环节我们看到,使用IntentService类来实现服务的启动很方便。但是如果你需要你的服务去执行多线程操作(而不是给到工作队列来处理),那你就需要继承Service类来处理请求。

作为对比,下面的代码是实现IntentService同样功能的Service实现。就是说,对所有的启动请求,它启动一个工作线程来执行任务并且一次处理一个请求。

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给新线程传入了一个“后台”的优先级也就是让它的高负荷任务不会影响到我们的UI
// 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()的请求,意味着你可以同时并行地处理多个请求,不再是像IntentService那样只能串行的处理。当然我们的例子里面并没有实现多线程,但只要你想实现,完全可以对每个请求都创建一个新线程并且启动他(而不是等到前一个请求结束之后才启动)。
注意到onStartCommand()方法是必须返回一个整型变量的。这个整型变量描述了在系统杀掉这个服务之后后续如何来处理它(在IntentService的默认实现中已经帮你处理了这个东西,当然你也可以修改)。这个整形变量的值应该是一下几个之一:

START_NOT_STICKY
如果系统在onStartCommand()返回之后杀掉了此服务,那么除非还有没处理的intent请求,否则不要再重新创建此服务了。这个选项是最安全的选项,它可以避免在不必要的时候随意启动服务;或者在你的应用可以轻松重启任何未完成的工作的时候,避免启动服务(因为应用自己可以处理,没必要启动服务)。
START_STICKY
如果系统在onStartCommand()返回之后杀掉了此服务,那么马上重启服务并且调用onStartCommand()方法,但是不要把上一个intent发过来。此时系统给你的onStartCommand()传入的是一个空的intent,或者,你当前还有未处理的请求启动服务的intent那就把未处理的给你传进来。这个选项适合于媒体播放(或者类似的服务)的场景,这些服务并没有在执行什么命令,而是在后台不停的运行着(比如mediaplayer,prepare之后start就可以开始循环播放了,然后就不执行什么代码了),等待任务。
START_REDELIVER_INTENT
如果系统在onStartCommand()返回之后杀掉了此服务,那么马上重启服务并且调用onStartCommand()方法,需要把上个intent发过来。然后如果还有未处理的intent就轮流发来。这个选项适用于那些正在主动执行一些需要立即返回的任务的服务,比如下载文件。
api文档里有相关的更详细的说明。

启动服务:
你可以通过在其他组件中调用startService()并传入一个intent对象来启动服务,然后系统会调用服务的onStartCommand()方法并把你的intent传过去。但是你可别自己调用onStartCommand()。
比如对于我们之前例子中的服务(HelloService)。在某活动内可以这样显式启动它:
Intent intent = new Intent(this, HelloService.class);
startService
(intent);
startService()方法会马上返回,然后系统就去调服务的onStartCommand()方法。如果那个服务当前并没有在运行,系统会先调onCreate()方法,然后再调onStartCommand()。
如果服务并没有提供绑定的功能,那上面方法就是组件和服务通信的唯一方法了。如果你想让服务返回一个结果,可以在客户端(就是组件这里,这例子里的活动)给广播创建一个PendingIntent(广播可以通过getBroadcast()得到)然后加到intent里一起发给服务。然后服务就可以用这个广播把结果发回来。
多个启动服务的请求会导致对onStartCommand()方法的多次调用。但是停止的话,调用一次stopSelf()或者stopService()就够了(因为服务的onCreate()只执行了一次)。

停止服务:
被启动的服务需要服务自己来管理生命周期。系统一般情况不会停止或销毁服务,除非需要清理内存。所以要么服务自己调stopSelf()要么别的组件调stopService()来停止服务。
一旦调用上述二方法,系统会尽快的销毁服务。
但是,如果你的服务可以并发的处理多个请求,那么处理完某个请求之后可别马上停止服务,因为你可能又收到了一个新的请求,在第一个请求结束时停止服务会将第二个请求也中止。为了避免此情况,可以用stopSelf(int)方法,保证你停止的服务仅仅是基于最近发出的那个请求。即,在stopSelf(int)的调用中把开启服务的请求id传进去(而这个请求id是在onStartCommand()方法中传给你的),然后就可以停止对应的服务。这样的话,如果在你调用stopSelf(int)之前服务又收到了一个新的请求,然后系统发现ID不匹配,所以此时即便stopSelf(int)也不会影响到新的请求。
注意:服务完成任务时应用一定要把它中止掉,这一点很重要可以避免浪费系统资源和消耗无谓的电量。如果必要的话,其他组件可以调用stopService()中止服务。就算你开启了绑定,只要服务接收过哪怕一次onStartCommand()的调用,你也还是要手动中止服务。(也就是说,本来绑定到服务只需解绑就可以停止服务,但是现在不只是绑定,服务同时还执行了onStartCommand()启动了,那么光解绑就不够了,让然需要stopService()或者stopSelf()。)
下面会详细讨论服务的生命周期相关的东西。

创建一个被绑定的服务:
被绑定的服务允许其他应用的组件通过bindService()绑定到它,然后便可以创建一个长期的连接(一般情况允许绑定的服务就不再允许被启动了)。
如果你希望在活动中或者其他组件中和服务进行交互,或者给其他应用暴露一些你的应用的功能(通过进程间通信IPC),那就需要使用绑定服务了。
那么怎么用?首先一定要实现onBind()回调方法并返回一个IBinder,这个IBinder定义了一个用来和服务通信的接口。然后其他应用的组件就可以调用bindService()方法去获得这个接口然后开始调用服务的方法。服务的存在就是为了给绑定到它的应用组件提供服务,所以如果没有任何组件绑定到服务,系统就会销毁它(和启动服务不一样,这里就不需要你调什么stop方法了)。
创建绑定服务,必须要定义一个接口,这个接口定义了客户端如何与服务通信。而这个接口必须是实现了IBinder的并且需要作为onBind()的返回值返回的。当客户端(客户端就是组件)收到了你这个实现了IBinder的接口之后,就可以开始通过接口和服务进行交互了。
多个客户端可以到同时绑定到同一个服务。当某个客户端完成了和服务的交互的时候,就可以调用unbindService()解绑服务。当所有的客户端都解绑了之后,服务没有绑定到任何客户端的情况下,系统会销毁服务。
绑定服务的实现要比启动服务复杂,所以有单独的一篇文档来讨论它。

给用户发送通知:
服务运行起来之后,可以通过ToastNotifications或者StatusBarNotifications给用户发送事件通知。
Toast通知是一个短暂出现在当前窗口表面的然后就消失的信息。状态栏通知则是在状态栏提供了一个图标和一段消息可以供用户选择,实现不同的动作(比如开启一个新活动)。
通常,某些后台任务完成之后用户可以对它进行一些操作了,此时最佳的通知方式是使用状态栏通知(比如应用下载完毕可以安装了什么的)。如果用户点击了下拉菜单的通知,这时可以开启一个新活动(比如安装软件)。

让服务在前台运行:
前台服务一般来说是指用户意识到它在运行的服务,所以系统内存不足的时候前台服务并不能作为一个“被杀备选项”。前台服务必须在状态栏提供一个通知,这个通知会被放在“正在运行”的提示下方,意思是这个通知不能被简单地一键清除,除非是服务被停止了或者被移出了前台。
比如,播放音乐的播放器服务应该运行在前台,因为用户是意识到了它的运行的(听到音乐了所以必然能意识到。。)。而这个放在状态栏的播放器前台服务可以告知用户当前播放的歌曲,并且允许用户打开播放器的交互活动进行操作。
若要让你的服务运行在前台,调用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()。传入一个boolean值,表示是否要把状态栏的对应通知也删掉。这个方法不会将服务停止。不过,如果你在前台服务运行期间把它停掉了,对应的通知图标也会删掉的。

管理服务的生命周期:
服务的生命周期比活动的要简单不少,不过对于服务的创建和销毁你需要格外的留心,因为服务是可以在用户意识不到的情况下在后台运行的。
服务的生命周期有两条路径:
被启动的服务:
在其他组件调用startService()的时候服务被创建。一直到自己调用stopSelf()或者其他组件调用stopService()服务才会停止,进而被系统销毁。
被绑定的服务:
在其他组件调用bindService()的时候服务被创建。客户端通过IBinder接口和服务进行通信。客户端可以通过unbindService()来关闭连接。多个客户端可以绑定到同一个服务然后当他们全部都解绑时,系统会销毁服务(服务不需要自行了断)。

这两条路径完全独立。也就是说,对于已经通过onStartCommand()启动的服务你同样可以绑定到它。比如,某后台音乐播放服务可以通过startService()并在传入的intent中指明要播放的歌曲来启动。之后,用户可能会想要对播放器做一些操作或者获取关于正在播放的曲目的信息,这时,某个活动就可以通过bindService()绑定到播放器服务进而进行交互。在这种情况下,即使你调用了stopSelf()或stopService()方法也不能停止服务,直到所有的客户端都和服务解绑。

实现生命周期回调方法:
像活动一样,服务也有一些生命周期回调方法,你可以实现这些方法来监测服务的状态变化并且在对应的时间点做一些操作。以下是一个基本框架示例:
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
}
}
注意:和活动的生命周期回调不一样,在服务的这些方法的实现中不需要调父类的方法。

通过实现这些方法,你可以监测到服务生命周期中两个嵌套的周期:
完整生命周期
服务的完整生命周期从onCreate()开始到onDestroy()结束。像活动一样,服务在onCreate()中做一些重要的初始化配置,在onDestroy()中做一些资源的释放动作。比如一个播放器服务可以在 onCreate()中创建播放音乐的线程然后在onDestroy()中停止线程。
有效的/激活的(active)生命周期
激活生命周期从onStartCommand()或者onBind()开始。两方法都会从系统收到一个intent,intent分别来自startService()和bindService()。如果服务是被启动的,那它的激活生命周期和完整生命周期的结束时间是一样的(onStartCommand()方法返回之后服务仍然是激活状态);如果服务是被绑定的,那么激活生命周期会在onUnbind()返回的时候结束。

注意:虽然被启动的服务可以通过调用stopSelf()stopService()来停止,但是服务的生命周期回调方法中并没有一个onStop()回调。所以,系统收到那两个stop调用的时候会直接销毁活动,即直接调onDestroy()方法(当然,绑定的情况另说)。

上面的生命周期图展示了服务的典型回调方法。虽然图中把两种方式分离开来讨论,但是一定记住,任何服务不管是如何启动的,都可能允许被绑定到客户端。所以一个被startService()启动起来调了自己的onStartCommand()方法的服务仍然可以通过bindService()调用自己的onBind()方法来接收绑定。














 posted on 2015-07-29 16:09  絮状颗粒  阅读(150)  评论(0)    收藏  举报