`
Jonathan樊
  • 浏览: 74936 次
  • 性别: Icon_minigender_2
  • 来自: 上海
社区版块
存档分类
最新评论

Android开发——Service的学习(上)

阅读更多

        Service是Android的重要组件之一,能够在后台,并且不需要用户界面的组件。其他的应用程序组件可以启动一个服务,即使用户切换到另一个应用程序,服务依然可以运行。服务运行在主线程中,如果要完成一些耗时的或者阻塞的工作,开发人员可以在服务中创建一个新的线程来完成这些工作。

 

        Service从本质上分为两种类型:Started(启动)和Bound(绑定)。

        

        Started:

        当应用程序组件通过startService()方法启动服务时,那么服务是started状态。一旦启动,服务就会在后台一直运行下去。 通常,started的服务执行单一的操作并且不会向调用者返回结果。 比如,它可以通过网络下载或上传文件。 当操作完成后,服务应该自行终止。

        Bound:

        当应用程序组件通过bindService()方法绑定到服务时,服务处于bound状态。bound服务提供了一个客户端/服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至可以利用进程间通信(IPC)跨进程执行这些操作。 绑定服务的生存期和被绑定的应用程序组件一致。 多个组件可以同时与一个服务绑定,不过所有的组件解除绑定后,服务也就会被销毁。

 

        服务可以只属于一种类型,也可以同时属于两种类型,既可以启动,也可以绑定。关键在于是否实现两个回调方法:onStartCommand()方法允许组件启动服务,onBind()方法允许组件绑定服务。

 

        一:Service的重要方法

        为了创建服务,必须创建Service类(或其存在的子类)的子类。在实现代码中需要重写一些回调方法,用于处理服务生命周期的一些关键节点,并且为组件提供绑定服务的机制。最重要的需要重写的回调方法如下:

        onStartCommand():

        当其他组件,比如一个activity,通过调用startService()请求started类型的服务时,系统将会调用这个方法。一旦这个方法执行,服务就会启动并且在后台一直运行下去。如果你的代码实现了本方法,你就有责任在完成工作后通过调用 stopSelf() 或 stopService() 终止服务(如果你只想提供bind方式,那就不需要实现本方法)。

        onBind():

        当其它组件需要通过 bindService() 绑定服务时(比如执行RPC),系统会调用这个方法。 在这个方法的实现代码中,你必须返回 IBinder 来提供一个接口,客户端用它来和服务进行通信。 你必须确保实现本方法,不过假如你不需要提供绑定,那就返回null即可。

        onCreat():

        当服务第一次被创建时,系统会调用此方法,用于执行一次性的创建过程(在系统调用onStartCommand()和onBind()前,调用此方法。如果服务依然运行,那么不会再调用此方法。

        onDestroy():

        当服务不再被使用并且将要被销毁时调用此方法。服务应该调用此方法去清理一些资源,比如线程,注册监听,接受者等等。如果服务已经运行,此方法不会被调用。

 

        如果组件调用onStart()方法启动服务(这会导致onStartCommand()被调用), 那么服务将一直保持运行,直至自行用 stopSelf() 终止或由其它组件调用 stopService() 来终止它。

        如果组件调用 bindService() 来创建服务(那 onStartCommand() 就不会被调用),则服务的生存期就与被绑定的组件一致。一旦所有客户端都对服务解除了绑定,系统就会销毁该服务。

 

        二:在Manifest中声明Service

        与activity(及其它组件)类似,你必须在应用程序的manifest文件中对所有的服务进行声明。要声明你的服务,把 <service> 元素作为子元素加入到 <application> 元素中去即可。例如:

 

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

        在 <service> 元素中可以包含很多其它属性,比如定义启动服务所需权限、服务运行的进程之类的属性。 android:name 是唯一必需的属性——它定义了服务的类名。应用程序一经发布,就不得再修改这个类名。因为这么做可能会破坏某些显式引用该服务的intent功能。

 

 

        三:创建Started服务

        Started Service 是由其他组件调用startService()方法启动的,这会导致onStartCommand()方法被调用。当服务是started状态时,其生命周期与启动它的组件无关,并且可以在后台无限期运行。因此服务需要自行用 stopSelf() 终止或由其它组件调用 stopService() 来终止它。

        诸如activity之类的应用程序组件,可以通过调用 startService() 启动服务,并传入一个给出了服务和服务所需数据的 Intent 对象。服务将在 onStartCommand() 方法中接收到该 Intent 对象

        

        例如,假定某activity需要把一些数据保存到在线数据库中。此activity可以启动一个companion service 并通过传递一个intent到 startService() 的方法把需要保存的数据发送给该服务。该服务在 onStartCommand() 内接收intent,连接Internet,再进行数据库事务处理。当事务完成后,服务自行终止,并被系统销毁。

 

        传统做法,你可以扩展两个类来创建started服务:

 

        Service类:

        这是所有服务的基类。如果你要扩展该类,则很重要的一点是:请在其中创建一个新的线程来完成所有的服务工作。 因为服务默认是使用应用程序的主线程的,这会降低应用程序中activity的运行性能。

 

        IntentService类:

        这是 Service 类的子类,它每次启动一个工作(worker)线程来处理所有的启动请求。 如果服务不需要同时处理多个请求的话,这是最佳的选择。 所有你要做的工作就是实现 onHandleIntent() 即可,它会接收每个启动请求的intent,然后就可在后台完成工作。

 

        继承IntentService类

        因为大多数started服务都不需要同时处理多个请求(实际上在多线程一下是危险的),所以最佳方式也许就是用 IntentService 类来实现上述的服务。

        

        IntentService 将执行以下步骤:

 

  • 创建一个默认的工作(worker)线程,它独立于应用程序主线程,来执行所有发送到 onStartCommand() 的intent。
  • 创建一个工作队列,每次向实现的 onHandleIntent() 传入一个intent,这样你就永远不必担心多线程问题了。
  • 在处理完所有的启动请求后,终止服务,因此你就永远不需调用 stopSelf() 了。
  • 提供默认的 onBind() 实现代码,它返回null。
  • 提供默认的 onStartCommand() 实现代码,它把intent送入工作队列,稍后会再传给onHandleIntent() 实现代码。

      以上说明:要做的全部工作就是实现 onHandleIntent() 的代码,来完成客户端提交的任务。由于IntentService类没有提供控参数的构造方法,所以你还需要为服务提供一小段构造方法)。以下是例子:

 

public class HelloIntentService extends IntentService {

  public HelloIntentService() {
      super("HelloIntentService");
  }
  
  @Override
  protected void onHandleIntent(Intent intent) {
      // 通常可以在这里添加任务代码, 比如下载一个文件.
      // 作为小例子,我们让他休眠5秒钟.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}

        继承IntentService类

 

        如上所述,利用 IntentService 来实现一个started服务非常简单。 不过,假如你的服务需要多线程运行(而不是通过一个工作队列来处理启动请求),那你可以扩展 Service 类来完成每个intent的处理。作为对照,以下例程实现了 Service 类,它执行的工作与上述使用 IntentService 的例子相同。确切地说,对于每一个启动请求,它都用一个工作线程来完成处理工作,并且每次只处理一个请求。

 

public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // 处理从线程接受到的消息
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // 通常可以在这里添加任务代码, 比如下载一个文件.
          // 作为小例子,我们让他休眠5秒钟.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // 根据startId停止服务,这样就确保不会在处理任务中间停止服务了 
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // 启动运行服务的线程.
    // 创建一个单独的线程,因为服务通常运行于进程的主线程中,可我们不想阻塞主线程。
    // 我们还要赋予它后台运行的优先级,以便计算密集的工作不会干扰我们的UI。
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // 获得线程的Looper,用来创建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();

      // 对于每一个启动请求,发送一个信息去启动一个任务,并且传递startID,这样就会知道在任务结束时,停止哪一个请求服务。
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);

      // 如果服务被杀死,在这里重启服务
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // 因为并不提供绑定,所以 return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

       

        四:启动服务

        从activity或其它应用程序组件中可以启动一个服务,调用 startService() 并传入一个 Intent (指定所需启动的服务)即可。Android系统将调用服务的 onStartCommand() 方法,并传入该 Intent。例如,一个activity可以用一个显式的intent通过 startService() 启动上一节的示例服务(HelloSevice):

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

         startService() 方法会立即返回,Android系统会去调用服务的 onStartCommand() 方法。如果服务还未运行,系统会首先调用 onCreate() ,然后再去调用 onStartCommand() 。

        如果服务不同时支持绑定,那么通过 startService() 传入的intent将是应用程序组件与服务进行交互的唯一途径。 当然,如果你期望服务能返回结果,那启动服务的客户端可以创建一个 PendingIntent 来获得一个广播broadcast(利用 getBroadcast() ),并把它放入启动服务的 Intent 并传到服务中去。然后服务就会用这个broadcast来传递结果。

        多个启动服务的请求将会引发服务 onStartCommand() 方法的多次调用。不过,仅仅需要一个终止服务的方法(用 stopSelf() 或 stopService() )来停止服务。

 

        五:停止服务

        一个started服务必须自行管理生命周期。也就是说,系统不会终止或销毁这类服务,除非必须恢复系统内存并且服务返回后一直维持运行。 因此,服务必须通过调用 stopSelf() 自行终止,或者其它组件可通过调用 stopService() 来终止它。

 

        用 stopSelf() 或 stopService() 的终止请求一旦发出,系统就会尽快销毁服务。

 

        不过,如果你的服务要同时处理多个 onStartCommand() 请求,那在处理启动请求的过程中,你就不应该去终止服务,因为你可能接收到了一个新的启动请求(在第一个请求处理完毕后终止服务将停止第二个请求的处理。 为了避免这个问题,你可以用 stopSelf(int) 来确保终止服务的请求总是根据最近一次的启动请求来完成。 也就是说,当你调用 stopSelf(int) 时,同时将启动请求的ID(发送给 onStartCommand() 的startId)传给了对应的终止请求。这样,如果服务在你可以调用 stopSelf(int) 时接收到了新的启动请求,会会因为ID不一样,将不会终止服务

 

 

           注:主要是翻译官网的内容,因为最好的学习资料还是在官网上啊

          http://developer.android.com/guide/components/services.html

 

2
0
分享到:
评论

相关推荐

    《Google Android开发入门与实战》

    1.5 更上一层楼——加入Android开发社区 【视频列表】 第2章 工欲善其事 必先利其器——搭建Android开发环境 第3章 清点可用资本——AndroidSDK介绍 第5章 千里之行始于足下——第一个应用HelloWorld 第7章 良好的...

    android开发入门与实战(上)

    第10章 一切为用户服务——Service应用实例 10.1 认识Service 10.2 使用Service 10.3 Service的生命周期 10.4 实例学习Service 10.4.1 精彩实例一——定时提醒 10.4.2 精彩实例二——音乐播放器 10.5 本章小结 第11...

    android开发入门与实战(下)

    第10章 一切为用户服务——Service应用实例 10.1 认识Service 10.2 使用Service 10.3 Service的生命周期 10.4 实例学习Service 10.4.1 精彩实例一——定时提醒 10.4.2 精彩实例二——音乐播放器 10.5 本章小结 第11...

    Android开发与应用——张荣,原书配套课件

    这是Android开发与应用,原书配套的课件,作者张荣,目录如下。 第1章 Android简介 1.1 手机操作系统 1.2 Android起源 1.3 Android特征 1.4 Android体系结构 1.4.1 应用层 1.4.2 应用框架层 1.4.3 ...

    Android应用开发详解

    Android开发基础,讲述了Android开发环境的搭建、Android常用工具的使用和第一个Android应用程序的开发 第二篇 技术篇 第3章 Android中的资源访问 Android 中的资源访问,讲述了如何定义和访问Android中的外部...

    《Google Android开发入门与实战》.pdf

     本书内容上涵盖了用android开发的大部分场景,从android基础介绍、环境搭建、sdk介绍、market使用,到应用剖析、组件介绍、实例演示等方面。从技术实现上,讲解了5个android平台下的完整综合实例及源代码分析,...

    老罗android开发视频教程全集百度网盘下载

    Android 是Google开发的基于Linux平台的开源手机操作系统。它包括操作系统、用户界面和应用程序—— 移动电话工作所需的全部软件,而且不存在任何...【第一版第十五章】老罗Android开发视频--百度地图实战开发(10集)

    安卓学习教材经验Android进阶学习资料安卓面试资料等文档资料合集(22个).zip

    安卓学习教材经验Android进阶学习资料安卓面试资料等文档资料合集(22个): Android For OpenCV的环境搭建 Android Glide框架 二次封装 ...初中级Android开发社招面试之Service及BroadcastReceiver.p

    Google Android SDK开发范例大全(PDF完整版4)(4-4)

    6.4 开始与停止系统服务——Service与Runnable整合并用 6.5 通过短信发送email通知——BroadcastReceiver与Intent整合 6.6 手机拨接状态——PhoneStateListener之onCallStateChanged 6.7 有来电,发送邮件通知——...

    Google Android SDK开发范例大全(PDF高清完整版1)(4-1)

    6.4 开始与停止系统服务——Service与Runnable整合并用 6.5 通过短信发送email通知——BroadcastReceiver与Intent整合 6.6 手机拨接状态——PhoneStateListener之onCallStateChanged 6.7 有来电,发送邮件通知——...

    Google.Android开发入门与实战

     《Android开发入门与实战》内容上涵盖了用Android开发的大部分场景,从Android基础介绍、环境搭建、SDK介绍、Market使用,到应用剖析、组件介绍、实例演示等方面。从技术实现上,讲解了5个Android平台下的完整综合...

    Google Android SDK开发范例大全(PDF高清完整版3)(4-3)

    6.4 开始与停止系统服务——Service与Runnable整合并用 6.5 通过短信发送email通知——BroadcastReceiver与Intent整合 6.6 手机拨接状态——PhoneStateListener之onCallStateChanged 6.7 有来电,发送邮件通知——...

    android开发入门教程

    第10章 一切为用户服务——Service应用实例 10.1 认识Service 10.2 使用Service 10.3 Service的生命周期 10.4 实例学习Service 10.4.1 精彩实例一——定时提醒 10.4.2 精彩实例二——音乐播放器 10.5 本章小结 第11...

    android开发资料大全

    新版Android开发教程及笔记-完整版 《Android中文教程》中文版 《android基础教程合集》 Android实例教程 会员贡献索引贴 实用Android开发工具和资源精选 APK权限大全 - Android必懂知识 最无私的Android资料...

    Google Android SDK开发范例大全的目录

    6.4 开始与停止系统服务——Service与Runnable整合并用 6.5 通过短信发送email通知——BroadcastReceiver与Intent整合 6.6 手机拨接状态——PhoneStateListener之onCallStateChanged 6.7 有来电,发送邮件通知——...

    Google Android开发入门与实战的代码

    第10章 一切为用户服务——Service应用实例 187 10.1 认识Service 187 10.2 使用Service 188 10.3 Service的生命周期 194 10.4 实例学习Service 194 10.4.1 精彩实例一——定时提醒 194 10.4.2 ...

Global site tag (gtag.js) - Google Analytics