http://blog.csdn.net/vipzjyno1/article/details/26004831

 
 

上一篇说到了通知栏Notification,提起通知栏,不得让人想到Service以及BroadcastReceive,作为android的4大组建的2个重要成员,我们没少和它们打交道。它们可以在无形中使我们的软件和网络、数据库、系统等进行交互,之后通过UI(Notification就是一种展示方式)把结果展现在我们面前。可以说,他们是android生命体系里面的神经系统,通过反射条件让身体展现不同的状态。在整个系统中,广播接收器充当着是传输者和监听者的角色,它把系统的一点点变化都反馈上去,之后做出改变。

通过这几篇博文讲讲BroadcastReceiver(广播接收器)和Service(服务),以及他们之间的联系。这一篇通过开发文档、源码和书籍中笔记总结分析下service这个类。

开发文档:http://developer.android.com/reference/android/app/Service.html

什么是服务?

service可以说是一个在后台运行的Activity,它不是一个单独的进程,它只需要应用告诉它要在后台做什么就可以了。

它要实现和用户的交互的话需要通过通知栏或则是发送广播,UI去接收显示。它的应用十分广泛,尤其是在框架层,应用更多的是对系统服务的调用。

服务有什么用

它用于处理一些不干扰用户使用的后台操作。如下载,网络获取。播放音乐,他可以通过INTENT来开启,同时也可以绑定到宿主对象(调用者例如ACTIVITY上)来使用。

概述

服务是一个应用程序组件代表应用程序执行一个长时间操作的行为,虽然不与用户交互或供应功能供其它应用程序使用。每个服务类必须有一个相应的包的AndroidManifest.xml中 <Service>声明。服务可以通过Context.startService()和Context.bindService()开始工作。它和其他的应用对象一样,在他的宿主进程的主线程中运行。

类组成

extends ContextWrapper implements ComponentCallbacks2

它继承至ContextWrapper,再上去就是Context,它的直接子类用很多,间接子类是InputMethodService,下面就随便说几个

1.InputMethodService

这个类提供了一个输入法的标准实现,一般的开发者是不会去考虑这个,输入法公司和ODM厂商则需要去考虑。

2.IntentService

它作为Service的子类,主要用于处理异步请求,防止线程的阻塞,所有的请求将在一个工作线程(HandlerThread)中处理,工作完成了,线程也就结束了。

3.MediaRouteProviderService

它主要用于设备启动和SD卡挂载时候执行多媒体文件的扫描工作。

4. NotificationListenerService

上一篇博文主要就是将通知栏(Android 通知栏Notification的整合 全面学习),这个类就是和通知栏有关,它主要用于接收来自系统调用的服务及新通知发布或删除。

5. RecognitionService

它是一个抽象服务类,如果开发者希望实现一个新的语音识别器时候,可以用到它。

服务的类型

按照使用范围分类:

1.本地服务(Local Service):用于应用程序内部

功能:用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。

使用:在Service可以调用Context.startService()启动,调用Context.stopService()结束。在内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次stopService()来停止。

2.远程服务(Remote Sercie):用于android系统内部的应用程序之间

功能:可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。

使用:可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服务。调用Context.bindService()方法建立连接,并启动,以调用  Context.unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。

按照运行类别分类分:

1.前台服务

前台服务需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成为 前台服务。

使用前台服务可以避免服务在后台运行的时候被系统KILL。

android官方描述如下:

Running a Service in the Foreground


A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.

For example, a music player that plays music from a service should be set to run in the foreground, because the user is explicitly aware of its operation. The notification in the status bar might indicate the current song and allow the user to launch an activity to interact with the music player.

To request that your service run in the foreground, call startForeground(). This method takes two parameters: an integer that uniquely identifies the notification and the Notification for the status bar. For example:

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, notification);

To remove the service from the foreground, call stopForeground(). This method takes a boolean, indicating whether to remove the status bar notification as well. This method does not stop the service. However, if you stop the service while it's still running in the foreground, then the notification is also removed.

Note: The methods startForeground() and stopForeground() were introduced in Android 2.0 (API Level 5). In order to run your service in the foreground on older versions of the platform, you must use the previoussetForeground() method—see the startForeground() documentation for information about how to provide backward compatibility.

For more information about notifications, see Creating Status Bar Notifications.

使用:可以看出,我们只需要在onStartCommand里面调用 startForeground方法让服务前台运行,然后再onDestroy里面调用stopForeground解除前台运行既可!

所以,例如手机中的音乐播放器,不管手机是否是在休眠状态,只要开始播放了,系统就不会去KILL这个服务,只有当停止播放音乐时,服务才可能会回收清除。

2.后台服务

后台服务就是处于后台运行的

生命周期:

图:左图:启动方式的生命周期     右图:绑定方式的生命周期

注意:本地服务中,onStart已经被onStartCommand方法取代,Service和Activity都是由Context类派生的,可以通过getApplicationContext()方法获取上下文对象,和Activity一样,它有着自己的生命周期,可是和Activity相比,它所执行的过程略有不同,如上图所示。

在服务分类中,提到了3种服务通信类型,一种是通过startService()直接启动服务,一种是通过bindService()的方式启动,2种启动方式对应的生命周期如上图所示。3.使用AIDL方式的Service

下面就说说2种服务的启动流程:

1.context.startService() 启动流程(后台处理工作):

context.startService()  -> onCreate()  -> onStartCommand()  -> Service running  -> context.stopService()  -> onDestroy()  -> Service stop 

所以调用startService的生命周期大致为:

onCreate(只在创建的时候调用一次直到被摧毁) --> onStartCommand (服务开启后,可多次调用) --> onDestroy

服务中的onStartCommand(Intent intent, int flags, int startId)方法会返回一个唯一的整数标识符来识别启动请求,启动请求可以是START_STICKY、START_STICKY_COMPATIBILITY、START_NOT_STICKY、START_REDELIVER_INTENT等,标志位可以是START_FLAG_REDELIVERY、START_FLAG_RETRY。

通过这种方式,服务并不会随着绑定组建的摧毁而摧毁,而是服务自我摧毁。(所以这种方式适用于文件下载,上传等请求自行运行的场景)。

从图中我们可以看出,onCreate方法只在创建时候被调用了一次,这说明:Service被启动时只调用一次onCreate()方法,如果服务已经被启动,在次启动的Service组件将直接调用onStartCommand()方法,通过这样的生命周期,可以根据自身需求将指定操作分配进onCreate()方法或onStartCommand()方法中。

2.context.bindService()启动流程(在本地同一进程内与Activity交互):

context.bindService()  -> onCreate()  -> onBind()  -> Service running  -> onUnbind()  -> onDestroy()  -> Service stop

bindService的生命周期简化为为:onCreate --> onBind --> onUnbind --> onDestory

通过该方法,服务启动时会调用onCreate()来启动服务,可是它不会调用onStartCommand() 方法,并且只有在所有的服务都接触了后,服务才会自动停止运行。通过服务的onBind()方法,可以获的一个客户端与服务器进行通信的IBdiner接口。IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。

注:绑定服务的Android组建在摧毁前应解除绑定,否则会造成内存泄漏。

3.使用AIDL方式的Service(进行跨进程通信)(这块不是很懂,这里就不提了)

使用方式

1.创建服务类

  1. public class MyService extends Service {}
public class MyService extends Service {}

2.在AndroidMainfest.xml文件中配置注册该Service

  1. <service android:name="服务类所在的包名.MyService" />
<service android:name="服务类所在的包名.MyService" />

3. 启动服务

(1)通过直接启动服务的方式:

  1. Intent intent = new Intent(getApplicationContext(), MyService.class);
  2. startService(intent);
	Intent intent = new Intent(getApplicationContext(), MyService.class);
startService(intent);

服务类中:

  1. @Override
  2. public void onCreate() {
  3. }
  4. @Override
  5. public int onStartCommand(Intent intent, int flags, int startId) {
  6. //接受传递过来的intent的数据等
  7. return START_STICKY;
  8. }
  9. @Override
  10. public void onDestroy() {
  11. }
	@Override
public void onCreate() {
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
//接受传递过来的intent的数据等
return START_STICKY;
} @Override
public void onDestroy() { }

(2)通过绑定启动服务的方式:

绑定一个服务,需要设置ServiceConnection和标志位,方法如下:

  1. bindService(Intent service, ServiceConnection conn, int flags)
bindService(Intent service, ServiceConnection conn, int flags)

ServiceConnection可以监听服务的状态,在进行服务绑定的时,其标志位可以为以下几种(这里列出3种):

1).Context.BIND_AUTO_CREATE

说明:表示收到绑定请求的时候,如果服务尚未创建,则即刻创建,在系统内存不足需要先摧毁优先级组件来释放内存,且只有驻留该服务的进程成为被摧毁对象时,服务才被摧毁

2).Context.BIND_DEBUG_UNBIND

说明:通常用于调试场景中判断绑定的服务是否正确,但容易引起内存泄漏,因此非调试目的的时候不建议使用

3).Context.BIND_NOT_FOREGROUND

说明:表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行,该标志位位于Froyo中引入。

注意:绑定服务的以异步方式运行的。绑定服务必须在当前的上下文环境中运行,某些场景中,通过上下文进行添加绑定接触方法如下:

  1. getApplicationContext().bindService(service, conn, flags)
getApplicationContext().bindService(service, conn, flags)

代码如下:

  1. /** 是否绑定 */
  2. boolean mIsBound = false;
  3. /** 绑定服务 */
  4. public void doBindService() {
  5. bindService(new Intent(MainActivity.this, LocalService.class), mConnection,Context.BIND_AUTO_CREATE);
  6. mIsBound = true;
  7. }
  8. /** 解除绑定服务 */
  9. public void doUnbindService() {
  10. if (mIsBound) {
  11. // Detach our existing connection.
  12. unbindService(mConnection);
  13. mIsBound = false;
  14. }
  15. }
  16. private ServiceConnection mConnection = new ServiceConnection() {
  17. @Override
  18. public void onServiceConnected(ComponentName name, IBinder service) {
  19. mBoundService = ((LocalService.LocalBinder) service).getService();
  20. Toast.makeText(MainActivity.this, "服务连接", Toast.LENGTH_SHORT)
  21. .show();
  22. }
  23. @Override
  24. public void onServiceDisconnected(ComponentName name) {
  25. mBoundService = null;
  26. Toast.makeText(MainActivity.this, "服务未连接", Toast.LENGTH_SHORT)
  27. .show();
  28. }
  29. };
	/** 是否绑定 */
boolean mIsBound = false; /** 绑定服务 */
public void doBindService() {
bindService(new Intent(MainActivity.this, LocalService.class), mConnection,Context.BIND_AUTO_CREATE);
mIsBound = true;
} /** 解除绑定服务 */
public void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
} private ServiceConnection mConnection = new ServiceConnection() { @Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBoundService = ((LocalService.LocalBinder) service).getService();
Toast.makeText(MainActivity.this, "服务连接", Toast.LENGTH_SHORT)
.show();
} @Override
public void onServiceDisconnected(ComponentName name) {
mBoundService = null;
Toast.makeText(MainActivity.this, "服务未连接", Toast.LENGTH_SHORT)
.show();
}
};

服务类中:

  1. @Override
  2. public void onCreate() {
  3. }
  4. /** 绑定的IBinder */
  5. private final IBinder mBinder = new LocalBinder();
  6. public class LocalBinder extends Binder {
  7. public LocalService getService() {
  8. return LocalService.this;
  9. }
  10. }
  11. @Override
  12. public IBinder onBind(Intent intent) {
  13. return mBinder;
  14. }
  15. @Override
  16. public boolean onUnbind(Intent intent) {
  17. // TODO Auto-generated method stub
  18. return super.onUnbind(intent);
  19. }
	@Override
public void onCreate() { }
/** 绑定的IBinder */
private final IBinder mBinder = new LocalBinder(); public class LocalBinder extends Binder {
public LocalService getService() {
return LocalService.this;
}
} @Override
public IBinder onBind(Intent intent) {
return mBinder;
} @Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}

4.停止服务

(1)启动服务停止有2种方法:

1)stopSelf()  自我停止服务

2)stopService(Intent name)    被动停止服务

(2)绑定服务的解除绑定方法如下:

  1. unbindService(ServiceConnection conn)
unbindService(ServiceConnection conn)

使用细节

1.在注册服务的时候,为了将service纳入编译系统,必须在AndroidMainfest.xml中对Service进行显式声明。

2.计算量较大的又不是UI层的工作的话,可以选择放置在Service中进行工作。

3.通过开发文档你会发现,Android中的Service与宿主(调用者)在同一线程,而不是专门起一条线程,这意味着,如果你的服务要CPU密集型操作(如:MP3播放)或则阻塞操作(如网络)时,必须产生它自己的线程来完成这个工作,否则会造成线程阻塞。在Service的子类里面,IntentService类服务可以作为一个标准的实施,它的工作有其自己的线程。

4.如果在使用Service的时候又使用了广播接收器配合工作,广播如果是动态注册的话,在服务停止的时候记得调用unregisterReceiver(receiver);这个方法来注销掉接收器

拓展

1.如何检查Android后台服务线程(Service类)是否正在运行

Android系统自己提供了一个函数ActivityManager.getRunningServices,可以列出当前正在运行的后台服务线程

  1. private boolean isServiceRunning() {
  2. ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
  3. for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
  4. if ("com.example.MyService".equals(service.service.getClassName())) {
  5. return true;
  6. }
  7. }
  8. return false;
  9. }
private boolean isServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if ("com.example.MyService".equals(service.service.getClassName())) {
return true;
}
}
return false;
}

2.Service与UI之间的通信方式

(1)使用直接启动的startService实现信息传递

流程:UI  ——>Service

操作:使用Intent进行数据传递,通过服务中的onStartCommand方法进行接受(和Activity间传递方式一样)

(2)使用绑定启动的bindservice实现信息传递(

流程:UI  ——>Service

(3)使用Broadcast(广播)进行信息的双向传递

流程:UI  <——>Service

操作:注册绑定广播接受器,之后通过广播来进行2者间通信

注意:在服务退出的时候记得unregisterReceiver(receiver);注销广播接收器

3.Service和Thread的区别

我们拿服务来进行一个后台长时间的动作,为了不阻塞线程,然而,Thread就可以达到这个效果,为什么我们不直接使用Thread去代替服务呢?(这个问题摘抄至网上,原文地址不是是哪个,所以没写上)

这里提下,

1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。 
2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!

既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止  Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。

举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何  Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。

因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

Service服务的

Android 服务类Service 的详细学习的更多相关文章

  1. Android 服务类Service 的具体学习

    上一篇说到了通知栏Notification,提起通知栏,不得让人想到Service以及BroadcastReceive,作为android的4大组建的2个重要成员,我们没少和它们打交道.它们能够在无形 ...

  2. Android服务类Service具体解析

    Service有什么作用? 很多人不明确service是用来干嘛的.事实上Service作为Android四大组件之中的一个,能够理解为一个执行在后台的Activity.它适用于处理一些不干扰用户的长 ...

  3. Android服务之Service(其一)

    android中服务是运行在后台的东西,级别与activity差不多.既然说service是运行在后台的服务,那么它就是不可见的,没有界面的东西.你可以启动一个服务Service来播放音乐,或者记录你 ...

  4. Android服务之Service

    android中服务是运行在后台的东西,级别与activity差不多.既然说service是运行在后台的服务,那么它就是不可见的,没有界面的东西.你可以启动一个服务Service来播放音乐,或者记录你 ...

  5. Spring容器装饰者模式应用之实现业务类与服务类自由组合的解决方式

    在不论什么一个项目中都不可或缺的存在两种bean,一种是实现系统核心功能的bean,我们称之为业务类,第二种是与系统核心业务无关但同一时候又提供十分重要服务bean,我们称之为服务类.业务类的bean ...

  6. Android(java)学习笔记234: 服务(service)之音乐播放器

    1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...

  7. Android(java)学习笔记229:服务(service)之绑定服务调用服务里面的方法 (采用接口隐藏代码内部实现)

    1.接口 接口可以隐藏代码内部的细节,只暴露程序员想暴露的方法 2.利用上面的思想优化之前的案例:服务(service)之绑定服务调用服务里面的方法,如下: (1)这里MainActivity.jav ...

  8. Android(java)学习笔记177: 服务(service)之音乐播放器

    1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...

  9. Android(java)学习笔记172:服务(service)之绑定服务调用服务里面的方法 (采用接口隐藏代码内部实现)

    1. 接口 接口可以隐藏代码内部的细节,只暴露程序员想暴露的方法 2. 利用上面的思想优化之前的案例:服务(service)之绑定服务调用服务里面的方法,如下: (1)这里MainActivity.j ...

随机推荐

  1. Mybaits学习总结2

    http://www.cnblogs.com/xdp-gacl/p/4262895.html 继续参考这篇文章写Mybaits学习总结 上一章,我修改了编码,统一为UTF8之后,便没有编码错误 < ...

  2. 继承进一步使用,以及super关键字

    目标: 1)掌握子类对象实例化过程 2)掌握方法覆盖概念和实现. 3)掌握super关键字的作用. 一,子类对象实例化过程 子类对象在实例化之前,必须先调用父类中的构造方法,再调用子类中的构造方法. ...

  3. 05Spring_Bean属性的集合类型的注入

  4. 【Windows phone 8】欢迎引导页面02

    [目标]前一篇文章已经实现了图片的切换,这里需要限制pivot的循环滚动. [思路]通过手势事件,对第一张,最后一张图片处加以限制 [前台] 在pivot处加上 <toolkit:Gesture ...

  5. Gruntjs: task之文件映射

    由于大多数的任务执行文件操作,Grunt提供了一个强大的抽象声明说明任务应该操作哪些文件.这里总结了几种src-dest(源文件-目标文件)文件映射的方式,提供了不同程度的描述和控制操作方式. 1. ...

  6. 异步编程 In .NET(转)

    转自:http://www.cnblogs.com/jesse2013/p/Asynchronous-Programming-In-DotNet.html 概述 在之前写的一篇关于async和awai ...

  7. word2010 数学公式/联立方程/大括号内方程组如何左对齐?

    如何在word中输入的联立方程使其条件左对齐? 如输入: 实现如下对齐: 就是在每个逗号 .前输入一个 & 号就可以了, 注意这个逗号一定要是 位于这个方框里头,然后在其前面输入 & ...

  8. 学习Shell脚本编程(第2期)_编写修改权限及执行Shell程序的步骤

    编写Shell程序 执行Shell程序 Shell程序有很多类似C语言和其他程序设计语言的特征,但是又没有程序语言那样复杂.Shell程序是指放在一个文件中的一系列Linux命令和实用程序.在执行的时 ...

  9. [CareerCup] 12.3 Test Move Method in a Chess Game 测试象棋游戏中的移动方法

    12.3 We have the following method used in a chess game: boolean canMoveTo( int x, int y). This metho ...

  10. Maven in 5 Minutes(Windows)

    这是根据官网的例子写的入门例子:http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html 1)下载maven: ...