Service的两种模式(startService()/bindService()不是完全分离的):

  • 本地服务Local Service 用于应用程序内部
    它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。
    用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。

  • 远程服务Remote Service 用于android系统内部的应用程序之间
    它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
    可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。

生命周期

Service的生命周期并不像Activity那么复杂,它只继承了onCreate(),onStart(),onDestroy()三个方法,当我们第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停止Service时,则执行onDestroy()方法,这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。

而启动service,根据onStartCommand的返回值不同,有两个附加的模式:

1. START_STICKY 用于显示启动和停止service。

2. START_NOT_STICKY或START_REDELIVER_INTENT用于有命令需要处理时才运行的模式。

服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。
1. 使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。
如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。


2. 使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。

看看官方给出的比较流程示意图:

官方文档告诉我们,一个service可以同时start并且bind,在这样的情况,系统会一直保持service的运行状态如果service已经start了或者BIND_AUTO_CREATE标志被设置。如果没有一个条件满足,那么系统将会调用onDestory方法来终止service.所有的清理工作(终止线程,反注册接收器)都在onDestory中完成。

拥有service的进程具有较高的优先级

官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。

1. 如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。

2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.

3. 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。

4. 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。

如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。


本地service

1.不需和Activity交互的本地服务

[java]view plaincopy

  1. publicclassLocalServiceextendsService{

  2. privatestaticfinalStringTAG="LocalService";

  3. @Override

  4. publicIBinderonBind(Intentintent){

  5. Log.i(TAG,"onBind");

  6. returnnull;

  7. }

  8. @Override

  9. publicvoidonCreate(){

  10. Log.i(TAG,"onCreate");

  11. super.onCreate();

  12. }

  13. @Override

  14. publicvoidonDestroy(){

  15. Log.i(TAG,"onDestroy");

  16. super.onDestroy();

  17. }

  18. @Override

  19. publicvoidonStart(Intentintent,intstartId){

  20. Log.i(TAG,"onStart");

  21. super.onStart(intent,startId);

  22. }

  23. }


Activity:

[java]view plaincopy

  1. publicclassServiceActivityextendsActivity{

  2. @Override

  3. protectedvoidonCreate(BundlesavedInstanceState){

  4. super.onCreate(savedInstanceState);

  5. setContentView(R.layout.servicedemo);

  6. ((Button)findViewById(R.id.startLocalService)).setOnClickListener(

  7. newView.OnClickListener(){

  8. @Override

  9. publicvoidonClick(Viewview){

  10. //TODOAuto-generatedmethodstub

  11. startService(newIntent("com.demo.SERVICE_DEMO"));

  12. }

  13. });

  14. ((Button)findViewById(R.id.stopLocalService)).setOnClickListener(

  15. newView.OnClickListener(){

  16. @Override

  17. publicvoidonClick(Viewview){

  18. //TODOAuto-generatedmethodstub

  19. stopService(newIntent("com.demo.SERVICE_DEMO"));

  20. }

  21. });

  22. }

  23. }


在AndroidManifest.xml添加:

[java]view plaincopy

  1. <serviceandroid:name=".LocalService">

  2. <intent-filter>

  3. <actionandroid:name="com.demo.SERVICE_DEMO"/>

  4. <categoryandroid:name="android.intent.category.default"/>

  5. </intent-filter>

  6. </service>

否则启动服务时会提示new Intent找不到"com.demo.SERVICE_DEMO"。

对于这类不需和Activity交互的本地服务,是使用startService/stopService的最好例子。

运行时可以发现第一次startService时,会调用onCreate和onStart,在没有stopService前,无论点击多少次startService,都只会调用onStart。而stopService时调用onDestroy。再次点击stopService,会发现不会进入service的生命周期的,即不会再调用onCreate,onStart和onDestroy。

而onBind在startService/stopService中没有调用。

2.本地服务和Activity交互

对于这种case,官方的sample(APIDemo\app.LocalService)是最好的例子:

[java]view plaincopy

  1. /**

  2. *Thisisanexampleofimplementinganapplicationservicethatrunslocally

  3. *inthesameprocessastheapplication.The{@linkLocalServiceController}

  4. *and{@linkLocalServiceBinding}classesshowhowtointeractwiththe

  5. *service.

  6. *

  7. *<p>Noticetheuseofthe{@linkNotificationManager}wheninterestingthings

  8. *happenintheservice.Thisisgenerallyhowbackgroundservicesshould

  9. *interactwiththeuser,ratherthandoingsomethingmoredisruptivesuchas

  10. *callingstartActivity().

  11. */

  12. publicclassLocalServiceextendsService{

  13. privateNotificationManagermNM;

  14. /**

  15. *Classforclientstoaccess.Becauseweknowthisservicealways

  16. *runsinthesameprocessasitsclients,wedon'tneedtodealwith

  17. *IPC.

  18. */

  19. publicclassLocalBinderextendsBinder{

  20. LocalServicegetService(){

  21. returnLocalService.this;

  22. }

  23. }

  24. @Override

  25. publicvoidonCreate(){

  26. mNM=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);

  27. //Displayanotificationaboutusstarting.Weputaniconinthestatusbar.

  28. showNotification();

  29. }

  30. @Override

  31. publicintonStartCommand(Intentintent,intflags,intstartId){

  32. Log.i("LocalService","Receivedstartid"+startId+":"+intent);

  33. //Wewantthisservicetocontinuerunninguntilitisexplicitly

  34. //stopped,soreturnsticky.

  35. returnSTART_STICKY;

  36. }

  37. @Override

  38. publicvoidonDestroy(){

  39. //Cancelthepersistentnotification.

  40. mNM.cancel(R.string.local_service_started);

  41. //Telltheuserwestopped.

  42. Toast.makeText(this,R.string.local_service_stopped,Toast.LENGTH_SHORT).show();

  43. }

  44. @Override

  45. publicIBinderonBind(Intentintent){

  46. returnmBinder;

  47. }

  48. //Thisistheobjectthatreceivesinteractionsfromclients.See

  49. //RemoteServiceforamorecompleteexample.

  50. privatefinalIBindermBinder=newLocalBinder();

  51. /**

  52. *Showanotificationwhilethisserviceisrunning.

  53. */

  54. privatevoidshowNotification(){

  55. //Inthissample,we'llusethesametextforthetickerandtheexpandednotification

  56. CharSequencetext=getText(R.string.local_service_started);

  57. //Settheicon,scrollingtextandtimestamp

  58. Notificationnotification=newNotification(R.drawable.stat_sample,text,

  59. System.currentTimeMillis());

  60. //ThePendingIntenttolaunchouractivityiftheuserselectsthisnotification

  61. PendingIntentcontentIntent=PendingIntent.getActivity(this,0,

  62. newIntent(this,LocalServiceController.class),0);

  63. //Settheinfofortheviewsthatshowinthenotificationpanel.

  64. notification.setLatestEventInfo(this,getText(R.string.local_service_label),

  65. text,contentIntent);

  66. //Sendthenotification.

  67. //Weusealayoutidbecauseitisauniquenumber.Weuseitlatertocancel.

  68. mNM.notify(R.string.local_service_started,notification);

  69. }

  70. }

这里可以发现onBind需要返回一个IBinder对象。也就是说和上一例子LocalService不同的是,

1. 添加了一个public内部类继承Binder,并添加getService方法来返回当前的Service对象;

2. 新建一个IBinder对象——new那个Binder内部类;

3. onBind方法返还那个IBinder对象。

Activity:

[java]view plaincopy

  1. /**

  2. *<p>Exampleofbindingandunbindingtothe{@linkLocalService}.

  3. *Thisdemonstratestheimplementationofaservicewhichtheclientwill

  4. *bindto,receivinganobjectthroughwhichitcancommunicatewiththeservice.</p>

  5. */

  6. publicclassLocalServiceBindingextendsActivity{

  7. privatebooleanmIsBound;

  8. privateLocalServicemBoundService;

  9. @Override

  10. protectedvoidonCreate(BundlesavedInstanceState){

  11. super.onCreate(savedInstanceState);

  12. setContentView(R.layout.local_service_binding);

  13. //Watchforbuttonclicks.

  14. Buttonbutton=(Button)findViewById(R.id.bind);

  15. button.setOnClickListener(mBindListener);

  16. button=(Button)findViewById(R.id.unbind);

  17. button.setOnClickListener(mUnbindListener);

  18. }

  19. privateServiceConnectionmConnection=newServiceConnection(){

  20. publicvoidonServiceConnected(ComponentNameclassName,IBinderservice){

  21. //Thisiscalledwhentheconnectionwiththeservicehasbeen

  22. //established,givingustheserviceobjectwecanuseto

  23. //interactwiththeservice.Becausewehaveboundtoaexplicit

  24. //servicethatweknowisrunninginourownprocess,wecan

  25. //castitsIBindertoaconcreteclassanddirectlyaccessit.

  26. mBoundService=((LocalService.LocalBinder)service).getService();

  27. //Telltheuseraboutthisforourdemo.

  28. Toast.makeText(LocalServiceBinding.this,R.string.local_service_connected,

  29. Toast.LENGTH_SHORT).show();

  30. }

  31. publicvoidonServiceDisconnected(ComponentNameclassName){

  32. //Thisiscalledwhentheconnectionwiththeservicehasbeen

  33. //unexpectedlydisconnected--thatis,itsprocesscrashed.

  34. //Becauseitisrunninginoursameprocess,weshouldnever

  35. //seethishappen.

  36. mBoundService=null;

  37. Toast.makeText(LocalServiceBinding.this,R.string.local_service_disconnected,

  38. Toast.LENGTH_SHORT).show();

  39. }

  40. };

  41. privateOnClickListenermBindListener=newOnClickListener(){

  42. publicvoidonClick(Viewv){

  43. //Establishaconnectionwiththeservice.Weuseanexplicit

  44. //classnamebecausewewantaspecificserviceimplementationthat

  45. //weknowwillberunninginourownprocess(andthuswon'tbe

  46. //supportingcomponentreplacementbyotherapplications).

  47. bindService(newIntent(LocalServiceBinding.this,

  48. LocalService.class),mConnection,Context.BIND_AUTO_CREATE);

  49. mIsBound=true;

  50. }

  51. };

  52. privateOnClickListenermUnbindListener=newOnClickListener(){

  53. publicvoidonClick(Viewv){

  54. if(mIsBound){

  55. //Detachourexistingconnection.

  56. unbindService(mConnection);

  57. mIsBound=false;

  58. }

  59. }

  60. };

  61. }

明显看出这里面添加了一个名为ServiceConnection类,并实现了onServiceConnected(从IBinder获取Service对象)和onServiceDisconnected(set Service to null)。

而bindService和unbindService方法都是操作这个ServiceConnection对象的。

AndroidManifest.xml里添加:

[java]view plaincopy

  1. <serviceandroid:name=".app.LocalService"/>

  2. <activityandroid:name=".app.LocalServiceBinding"android:label="@string/activity_local_service_binding">

  3. <intent-filter>

  4. <actionandroid:name="android.intent.action.MAIN"/>

  5. <categoryandroid:name="android.intent.category.SAMPLE_CODE"/>

  6. </intent-filter>

  7. </activity>

这里没什么特别的,因为service没有需要什么特别的action,所以只是声明service而已,而activity和普通的没差别。

运行时,发现调用次序是这样的:

bindService:

1.LocalService : onCreate
2.LocalService : onBind
3.Activity: onServiceConnected

unbindService: 只是调用onDestroy

可见,onStart是不会被调用的,而onServiceDisconnected没有调用的原因在上面代码的注释有说明。

介绍onStartCommand()需要用到的几个常量(引自官方文档)

START_NOT_STICKY

  • If the system kills the service after onStartCommand() returns,do notrecreate the service, unless there are pending intents to deliver. This is the safest option to avoid running your service when not necessary and when your application can simply restart any unfinished jobs.

  • START_STICKY

  • If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), butdo notredeliver the last intent. Instead, the system calls onStartCommand() with a null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job.

  • START_REDELIVER_INTENT

  • If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand() with the last intent that was delivered to the service. Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as do wnloading a file.


Running a Service in the Foreground

具体内容查看官方文档,主要是使用 startForeground() 和 stopForeground()方法。


更多相关文章

  1. Android(安卓)KeyEvent分发机制
  2. Android(安卓)Inflate方法
  3. API Demos 2.2 研读笔记(10)——Redirection, Reorder Activity an
  4. android Launcher之获取安装的app列表的两种方法
  5. android 控制震动强度
  6. Android的Fragment中onActivityResult不被调用的终极解决方案
  7. Android使用广播(BroadCast)实现强制下线的方法
  8. Google Map API Key 获得方法
  9. (四十一) Android(安卓)O SystemServer初探

随机推荐

  1. android 音频系统java部分代码阅读
  2. Android下高斯模糊的算法和demo
  3. 【Android】The application has stopped
  4. 转载:android 源码 打包成apk的实现
  5. Android(安卓)超简单自动无限轮播图LoopV
  6. android 5.0新特性学习--CardView
  7. Android(安卓)ANR 分析流程
  8. Android WebView与Javascript交互
  9. Android 2.2 API demo
  10. Android jni调用第三方so库和.h文件