对于需要长期运行,例如播放音乐、长期和服务器的连接,即使已不是屏幕当前的activity仍需要运行的情况,采用服务方式。服务将通过API触发启动或者通过IPC(Interprocess Communication)连接请求触发启动。服务将一直运行直至被关闭,或者内存不足时由系统关闭。一般而言,为了节省电量,服务应进行优化减少CPU的消耗和大量网络通信。服务可用于以下的场景:

1、用户离开activity后,仍需继续工作,例如从网络下载文件,播放音乐
2、无论activity出现(重现)或离开,都需持续工作,例如网络聊天应用 
3、连接网络服务,正在使用一个远程API提供的服务 
4、定时触发的服务,例如Linux中的cron。

Services主要有两种形式:

  (1)started形式:调用startedservice()启动,需要显式关闭,一般情况下一个service只负责一项操作,不向调用者返回结果。比如从网络上下载文件等。操作完成之后,service应该主动退出。

  (2)Bound形式:其他组件调用bindservice()和此service绑定。

Service基础:

  一般通过继承Service类来创建一个service,并且需要重写一些重要的方法,这些方法管理service生命周期或者用于其它组件绑定此服务,主要有以下方法:

  onstartCommand():当其它组件(比如一个Activity)调用startService()时,系统调用onstartCommand()。这个方法调用后,service在后台开启,要结束这个service,必须自己调用stopself()或者其它组件调用stopService()。

  onBind():当其他组件调用bindService()绑定这个服务时,系统调用onBind()。这个方法中必须包含一个返回IBinder,用于服务和客户端通信的接口。

  onCreate():当service第一次被创建时调用,在onstartCommand()和onBind()之前被调用。

  onDestory():service()关闭时调用,释放资源,结束相关线程。

在manifest文件中声明service:

  <service>元素作为<application>元素的子项

  1. <manifest ... >
  2. ...
  3. <application ... >
  4. <service android:name=".ExampleService" />
  5. ...
  6. </application>
  7. </manifest> 

创建Started类型的service

  其它组件调用startService()启动service,系统随之调用service的onstartCommand()。service一旦启动,必须自己调用stopSelf(),或者其它组件调用stopService()才能结束它。

  其它组件可以通过startservice()传递一个携带着数据的Intent给service,service端在onstartCommand()中接收传递过来的Intent。

一般情况下,可以通过继承以下两个类来创建service:

  Service:这种Service默认使用程序的主线程,使用时最好自己创建一个新线程来处理服务工作。

  IntentService:它是Service的子类,使用一个工作线程来处理请求,但是每次只能处理一个请求,不能同时处理多个请求。它需要实现onHandleIntent()方法来接收intent,处理客户端请求。

通过继承IntentService类创建:

IntentService的工作流程如下:

  • 创建一个独立于主线程的的工作线程,执行传递给onstartCommand()的Intent。  
  • 创建一个工作队列,每次传递一个Intent给onHandleIntent()。
  • 所有请求被处理完后,Service会自动退出,不需要显式调用stopself()。
  • 默认提供的onBind()返回null。
  • onstartCommand()将Intent发送给一个工作队列,然后交给onHandleIntent()处理。

注意:需要实现onHandleIntent()方法和Service的构造器

继承IntentService的例子:

  1. public class HelloIntentService extends IntentService {
  2.  
  3. /**
  4. * 需要一个构造器, 必须调用父类构造器 IntentService(String)
  5. * 并传入要创建的工作线程的名字
  6. */
  7. public HelloIntentService() {
  8. super("HelloIntentService");
  9. }
  10.  
  11. /**
  12. * IntentService在工作线程中调用这个方法
  13. * 此方法返回后, IntentService关闭Service
  14. */
  15. @Override
  16. protected void onHandleIntent(Intent intent) {
  17. //一般情况下,我们在此做一些操作,比如下载一个文件。
  18. //对于这个例子,我们只是让线程睡眠5s
  19. long endTime = System.currentTimeMillis() + 5*1000;
  20. while (System.currentTimeMillis() < endTime) {
  21. synchronized (this) {
  22. try {
  23. wait(endTime - System.currentTimeMillis());
  24. } catch (Exception e) {
  25. }
  26. }
  27. }
  28. }
  29. } 

  如果需要重写其它方法,比如:onCreate(),onstartCommand(),或者onDestroy(),一定要先调用父类实现,这样IntentService才能正确处理工作线程的生命周期。

  比如,onstartCommand()必须返回默认实现(它表示怎样将Intent传递给onHandleIntent())。

  1. @Override
  2. public int onStartCommand(Intent intent, int flags, int startId) {
  3. Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
  4. return super.onStartCommand(intent,flags,startId);
  5. }

  除了onHandleIntent(),唯一一个不需要调用父类的方法是onBind(),但是Service在允许被绑定时才需要实现它。

通过继承Service类创建

  如果你需要创建一个Service来执行多线程的操作(而不是通过工作队列依次响应客户端的请求),你可以通过继承Service类来创建。

  下面是用继承Service类的方式创建服务的代码,代码执行的操作和上面IntentService方式代码执行的操作一样,它使用一个工作线程来执行操作,并且每次只能相应一个请求。

  1. public class HelloService extends Service {
  2. private Looper mServiceLooper;
  3. private ServiceHandler mServiceHandler;
  4.  
  5. // Handler that receives messages from the thread
  6. private final class ServiceHandler extends Handler {
  7. public ServiceHandler(Looper looper) {
  8. super(looper);
  9. }
  10. @Override
  11. public void handleMessage(Message msg) {
  12. // Normally we would do some work here, like download a file.
  13. // For our sample, we just sleep for 5 seconds.
  14. long endTime = System.currentTimeMillis() + 5*1000;
  15. while (System.currentTimeMillis() < endTime) {
  16. synchronized (this) {
  17. try {
  18. wait(endTime - System.currentTimeMillis());
  19. } catch (Exception e) {
  20. }
  21. }
  22. }
  23. // Stop the service using the startId, so that we don't stop
  24. // the service in the middle of handling another job
  25. stopSelf(msg.arg1);
  26. }
  27. }
  28.  
  29. @Override
  30. public void onCreate() {
  31. // Start up the thread running the service. Note that we create a
  32. // separate thread because the service normally runs in the process's
  33. // main thread, which we don't want to block. We also make it
  34. // background priority so CPU-intensive work will not disrupt our UI.
  35. HandlerThread thread = new HandlerThread("ServiceStartArguments",
  36. Process.THREAD_PRIORITY_BACKGROUND);
  37. thread.start();
  38.  
  39. // Get the HandlerThread's Looper and use it for our Handler
  40. mServiceLooper = thread.getLooper();
  41. mServiceHandler = new ServiceHandler(mServiceLooper);
  42. }
  43.  
  44. @Override
  45. public int onStartCommand(Intent intent, int flags, int startId) {
  46. Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
  47.  
  48. // For each start request, send a message to start a job and deliver the
  49. // start ID so we know which request we're stopping when we finish the job
  50. Message msg = mServiceHandler.obtainMessage();
  51. msg.arg1 = startId;
  52. mServiceHandler.sendMessage(msg);
  53.  
  54. // If we get killed, after returning from here, restart
  55. return START_STICKY;
  56. }
  57.  
  58. @Override
  59. public IBinder onBind(Intent intent) {
  60. // We don't provide binding, so return null
  61. return null;
  62. }
  63.  
  64. @Override
  65. public void onDestroy() {
  66. Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  67. }
  68. }

很显然,这种方式要比使用IntentService麻烦一些。

  但是,这种方式下可以为每个请求分别创建一个工作线程(上面代码没有这样做),这样多个请求就可以被同时执行(而不是要等上一个请求完成后才能执行下一个请求)。

  从上面代码中我们注意到,onStartCommand()方法返回一个整型常量。系统根据返回的这个常量来决定一个Service被杀死后怎样来回复它。常量有以下三种:START_NOT_STICKY,不重新创建Service,除非还有新的Intent要传递给它;START_STICKY,重新创建Service并调用onStartCommand(),但是不向它传递之前的Intent,调用onStartCommand()时向它传递null作为Intent。新的Intent可以传递给它;START_REDELIVER_INTENT,重新创建Service并调用onStartCommand(),向onStartCommand()传递之前的Intent,新的Intent也会依次传递给它。

启动一个Service

  可以在一个Activity或者其它组件中调用带有Intent参数的startService()来启动一个Service。然后系统就调用Service的onStartCommand()方法并把Intent传递给它。

例如:

  1. Intent intent = new Intent(this, HelloService.class);
  2. startService(intent);

关闭一个Service:

  Service必须管理自己的生命周期,系统不会主动关闭或者销毁一个Service(除非极少数情况下系统内存不足并且Service的onStartCommand()方法已经返回)。Service可以通过调用stopself()来关闭自己,其它组件可以调用stopService()来关闭某个服务。

  但是,如果你的Service正在处理多个请求,当你完成一个请求时不能马上关闭Service,因为这时很有可能Service又接收到了一个新的请求并且准备处理。为了避免这种情况,你可以使用stopSelf(int),参数是你要关闭的请求的ID,如果已经有新的请求被接收,那么要关闭的请求ID和新接收的请求的ID不同,Service将不会被关闭。

创建一个BoundService

  Bound Service就是其它组件调用bindService()和一个Service绑定起来,从而创建一个持久的通信。

  创建bound Service时,

Services学习(一)的更多相关文章

  1. Windows Services 学习(转载)

    转载:http://blog.csdn.net/fakine/article/details/42107571 一.学习点滴 1.本机服务查看:services.msc /s2.服务手动安装(使用sc ...

  2. 用C#创建Windows服务(Windows Services)

    用C#创建Windows服务(Windows Services) 学习:  第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...

  3. WCF学习资源收集汇总

    1.WCF编程 http://www.cnblogs.com/wengyuli/category/217446.html 2.wcf热门问题编程示例 http://blog.csdn.net/book ...

  4. SSIS 学习(9):包部署常见问题汇总【转】

    Integration Services 包在部署过程中,经常会出现这样那样的问题,让人摸不着头脑,很是烦人.下面我就将我在部署过程中,遇到的一些问题整理出来,以供大家参考. (一)SSIS包在SQL ...

  5. C#静态调用带有SoapHeader验证的WebServices

    转自:http://blog.csdn.net/u012995964/article/details/54562111 本文记录带有SoapHeader验证的WebServices服务创建.部署及C# ...

  6. AngularJs学习笔记--Injecting Services Into Controllers

    原版地址:http://docs.angularjs.org/guide/dev_guide.services.injecting_controllers 把service当作被依赖的资源加载到con ...

  7. AngularJs学习笔记--Creating Services

    原版地址:http://docs.angularjs.org/guide/dev_guide.services.creating_services 虽然angular提供许多有用的service,在一 ...

  8. 【2016-10-26】【坚持学习】【Day13】【WCF】【EF + Data Services】

    今天做了一个demo, EF+Data Services 先建立一个网站项目 添加一个ADO.NET 数据模型 相当于一个EF容器,用来连接MSSQL数据库 添加一个WCF Data Services ...

  9. AngularJS学习---REST和自定义服务(REST and Custom Services) ngResource step 11

    1.切换目录 git checkout step- npm start 2.效果图 效果图和step 10的没有什么差别,这里主要的改动都是代码,代码做了很多优化,这里效果图就不再贴出来了. 3.实现 ...

随机推荐

  1. 微软CRM解决医药企业串货之痛

    没有准确.及时的流向数据统计和分析,医药企业营销部门就无法有效管理串货泛滥问题,串货会造成渠道无利可赚,挫伤渠道的积极性,产品无人愿意卖,最终伤害的还是医药企业. 医药企业营销发展的不同阶段对串货的态 ...

  2. rman 命令

    OS: Oracle Linux Server release 5.7 DB: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - ...

  3. 基于opencv 的图片模糊判断代码

    #include"cv.h"  #include"highgui.h"  #include<iostream>  using namespace s ...

  4. 条款24:若所有的函数参数可能都需要发生类型转换才能使用,请采用non-member函数

    假设有一个有理数类Rational,有一个计算有理数乘法的成员函数operator*,示例如下: #include <iostream> class Rational { public: ...

  5. 浅谈.NET中闭包

    什么是闭包 闭包可以从而三个维度来说明.在编程语言领域,闭包是指由函数以及与函数相关的上下文环境组合而成的实体.通过闭包,函数与其上下文变量之间建立起关联关系,上下文变量的状态可以在函数的多次调用过程 ...

  6. DHCP Server软件使用教程

    DHCP Server软件使用教程 前提网络环境配置 电脑连接上wifi 网络和共享中心中更改适配器,共享无线网卡给以太网网卡 手动设置以太网网卡ipv4地址为192.168.1.1,子网掩码为255 ...

  7. Oracle Insert 多行(转)

    1.一般的insert 操作. 使用语法insert into table_name[(column[,column...])] values (value[,value…])的insert语句,每条 ...

  8. ATR与ATS

    ATR:answer to reset  复位应答 ATS:answer to select 选择应答

  9. Android -- 获取摄像头帧数据解码

    由于Android下摄像头预览数据只能  ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...

  10. 针对《来用》的NABC分析

    项目名:<来用> 特点:拥有以往win7在内的众多小游戏 NABC分析 N(need需求): 之所以有这个想法是因为,在WIN7,XP系统中往往有很多众所周知的小游戏(比如扫雷),但是在w ...