前言

  本篇博客聊一下Android下的Service组件,对于Service组件,有点类似于Windows下的服务。Service是Android四大组件中与Activity最相似的组件,它们的区别在于:Service一直在后台运行,它没有用户界面。一旦Service被启动起来之后,它就与Activity一样,也具有自己的生命周期。

  在开发过程中,对于Activity与Service的选择标准是:如果某个程序组件需要在运行时向用户呈现某种界面,或者该程序需要与用户交互,就需要使用Activity,否则就应该考虑使用Service。

  本篇博客主要内容:

  1. Service概述
  2. Service清单文件配置
  3. Service开发步骤
  4. startService
  5. bindService
  6. Service的适用场景

Service概述

  与开发一个Activity类似,它需要继承Service这个抽象类,并在实现类中,需要重写一些回调方法,用于处理Service的生命周期各部分的操作。而Service也是继承自Context,因此它也可以调用Context里定义的如getResource()、getContentResolver()等方法。

  Service中定义的生命周期方法,对Service服务的开发大部分工作就围绕以下几个方法进行操作:

  • void onCreate():当该Service第一次被创建后将立即回调该方法。
  • void onStartCommand(Intent intent,int flags,int startId):每次通过startService()方法启动Service时都会被回调。
  • void onDestroy():当Service被关闭前会被回调。
  • abstract IBinder onBind(Intent intent):该方法是Service子类必须实现的方法,如果不需要通过绑定的方式启动服务,可以返回Null。
  • boolean onUnbind(Intent intent):当Service上绑定的所有客户端都断开连接将回调该方法。

  通过服务的启动方式与适用范围,可将服务分为两类服务:

  • start:启动服务,当一个Android组件(如一个Activity)调用startService()的时候,启动一个服务。服务一旦启动,就可以一直在后台运行下去,即使这个启动它的组件被摧毁。这样的服务模式,通常用于执行一个操作而不需要返回结果给调用者。
  • Bound:绑定服务,当一个Android组件(如一个Activity)调用bindService()。一个绑定服务提供了一个客户端到服务端的接口,允许组件与服务之间进行交互,这样可以实现跨进程的通信。绑定服务的生命周期默认是跟随它的绑定组件的,但是一个绑定服务可以绑定多个Android组件,如果这些Android组件都被销毁,那么这个绑定服务也将被销毁。

  虽然上面提到了服务有两种类别,但是一个服务类所要继承的类是一样的,都是Service类。也就是说,一个服务,可以包含上面两种运行方式的服务,只是与它重载的方法有关,如果重写了onStartCommand()即支持启动服务,如果重写onBiind()即支持绑定服务,所以如果同时重载实现这两个方法即可实现两种服务。

  而对于两种启动方式的服务,生命周期中被回调的方法也不一样,下图明确说明了Service两种情况下的生命周期:

清单文件的配置

  Service是Android四大组件之一,所以它也必须在 AndroidManifest清单文件中进行配置,否则系统将找不到这个服务。与Activity一样,Service的配置也是在<application/>节点下,使用<service/>配置,其中android:name属性为Service类。

  如果开发的服务需要被外部应用操作,还需要配置<intent-filter/>节点,但是如果仅本程序使用,则无需配置它也可以。

  如果这个服务强制仅本应用操作,可以配置<service/>节点的android:exported属性为false,这样即使配置了<intent-filter/>,外部应用也无法操作这个服务,android:exported属性默认为true。

  清单文件配置示例:

  1. <application>
  2. <!-- 普通的服务 -->
  3. <service android:name=".Service1"></service>
  4. <!-- 可被外部应用访问的服务 -->
  5. <service android:name=".Service2">
  6. <intent-filter >
  7. <action android:name="com.bgxt.Service2"/>
  8. </intent-filter>
  9. </service>
  10. <!-- 无法被外部应用访问的服务 -->
  11. <service android:name=".Service3" android:exported="false">
  12. <intent-filter >
  13. <action android:name="com.bgxt.Service3"/>
  14. </intent-filter>
  15. </service>
  16. </application>

Service的开发步骤

  既然Service是一个与Activity类似的Android组件,所以它的开发步骤大致也为一下几步:

  1. 开发一个服务类,需要继承Service或者IntentService。
  2. 在AndroidManifest清单文件中注册Service组件。
  3. 在一个Android组件中启动这个开发的Service组件。
  4. 服务使用完成之后,需要停止这个服务。

启动服务

  启动服务必须实现Service.onStartCommond()方法。启动服务使用startService(Intent intent)方法开启一个服务,仅需要传递一个Intent对象即可,在Intent对象中指定需要启动的服务。而使用startService()方法启动的服务,在服务的外部,必须使用stopService()方法停止,在服务的内部可以调用stopSelf()方法停止当前服务。一旦使用startService()或者stopSelf()方法请求停止服务,系统会就会尽快销毁这个服务。

  对于启动服务,一旦启动将与访问它的组件无任何关联,即使访问它的组件被销毁了,这个服务也一直运行下去,直到被销毁!

启动服务-示例

  下面开发一个简单的使用startService()启动的服务,首先开发一个服务类:

  1. package com.example.intentdemo2;
  2.  
  3. import android.app.Service;
  4. import android.content.Intent;
  5. import android.os.IBinder;
  6. import android.util.Log;
  7.  
  8. public class StartService extends Service {
  9. private final static String TAG = "main";
  10.  
  11. @Override
  12. public IBinder onBind(Intent arg0) {
  13. // 仅通过startService()启动服务,所以这个方法返回null即可。
  14. return null;
  15. }
  16.  
  17. @Override
  18. public void onCreate() {
  19. super.onCreate();
  20. Log.i(TAG, "Service is Created");
  21. }
  22.  
  23. @Override
  24. public int onStartCommand(Intent intent, int flags, int startId) {
  25. Log.i(TAG, "Service is started");
  26. return super.onStartCommand(intent, flags, startId);
  27. }
  28.  
  29. @Override
  30. public void onDestroy() {
  31. Log.i(TAG, "Service is Destroyed");
  32. super.onDestroy();
  33. }
  34.  
  35. }

  虽然这个Service类没有什么处理逻辑,但是它包含了Service框架,在实际开发过程中,只需要在其中回调的方法中加入实际的业务实现代码即可。下面再使用一个Activity来操作这个服务,在这个Activity中有两个按钮,分别用于启动和停止这个服务。

  1. package com.example.intentdemo2;
  2.  
  3. import android.app.Activity;
  4. import android.content.ComponentName;
  5. import android.content.Intent;
  6. import android.os.Bundle;
  7. import android.util.Log;
  8. import android.view.View;
  9. import android.widget.Button;
  10.  
  11. public class ServiceActivity1 extends Activity {
  12. private Button btnSer1, btnSer2;
  13. private Intent service=null;
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_service1);
  18. btnSer1 = (Button) findViewById(R.id.btnSer1);
  19. btnSer2 = (Button) findViewById(R.id.btnSer2);
  20. // 设置服务启动的Intent
  21. service=new Intent(ServiceActivity1.this,StartService.class);
  22. btnSer1.setOnClickListener(new View.OnClickListener() {
  23.  
  24. @Override
  25. public void onClick(View v) {
  26. // 启动服务
  27. startService(service);
  28. }
  29. });
  30.  
  31. btnSer2.setOnClickListener(new View.OnClickListener() {
  32.  
  33. @Override
  34. public void onClick(View v) {
  35. // 停止服务
  36. stopService(service);
  37. }
  38. });
  39. }
  40. }

  执行结果均在日志中,可以在LogCat中查看,先启动服务,再停止服务:

  

绑定服务

  如果Service和宿主之间需要进行方法调用或者数据交换,则应该使用Context对象的bindService()和unbindService()方法来绑定和解除绑定服务。

  Context的bindService()方法的完整方法签名为:

    bindService(Intent service,ServiceConnection conn,int flags)

  下面简单介绍一下这个方法的三个参数的意义:

  • service:通过Intent指定要绑定的Service。
  • conn:一个ServiceConnection对象,该对象用于监听访问者与Service对象的onServiceConnected()方法。
  • flags:指定绑定时是否自动创建Service。0不自动创建、BIND_AUTO_CREATE,自动创建。

  从上面的bindService方法可以看出,绑定一个服务于宿主交互,依托于一个ServiceConnection接口,这个接口对象必须声明在主线程中,通过实现其中的两个方法,来实现与Service的交互,下面分别介绍一下这两个方法:

  • void onServiceConnection(ComponentName name,IBinder service):绑定服务的时候被回调,在这个方法获取绑定Service传递过来的IBinder对象,通过这个IBinder对象,实现宿主和Service的交互。
  • void onServiceDisconnected(ComponentName name):当取消绑定的时候被回调。但正常情况下是不被调用的,它的调用时机是当Service服务被意外销毁时,例如内存的资源不足时这个方法才被自动调用。

  在使用绑定的服务的时候,该Service类必须提供一个IBinder onBind(Intent intent)方法,在绑定本地Service的情况下,onBind()方法说返回的IBinder对象会传给宿主的ServiceConnection.onServiceConnected()方法的service参数,这样宿主就可以通过IBinder对象与Service进行通信。实际开发中一般会继承Binder类(IBinder的实现类)的方式实现自己的IBinder对象。

  需要注意的是,如果绑定服务提供的onBind()方法返回为Null,则也可以使用bindService()启动服务,但不会绑定上Service,因此宿主的ServiceConnection.onServiceConnected()方法不会被执行,也就不存在于宿主与服务的交互。

绑定服务-示例

  说了这么多绑定服务相关的内容,下面通过一个例子来实现Service的绑定与数据交互。

  开发一个Service类,用于进行绑定,在Service类中,做一个简单的数值累加,每秒加一。

  1. package com.example.intentdemo2;
  2.  
  3. import android.app.Service;
  4. import android.content.Intent;
  5. import android.os.Binder;
  6. import android.os.IBinder;
  7. import android.util.Log;
  8.  
  9. public class BindService extends Service {
  10. private final static String TAG = "main";
  11. private int count;
  12. private boolean quit;
  13.  
  14. private Thread thread;
  15. private MyBinder binder=new MyBinder();
  16. public class MyBinder extends Binder
  17. {
  18. // 声明一个方法,把count暴露给外部程序。
  19. public int getCount(){
  20. return count;
  21. }
  22. }
  23.  
  24. @Override
  25. public void onCreate() {
  26. super.onCreate();
  27. Log.i(TAG, "Service is Created");
  28. thread=new Thread(new Runnable() {
  29. @Override
  30. public void run() {
  31. // 每间隔一秒count加1 ,直到quit为true。
  32. while(!quit){
  33. try{
  34. Thread.sleep(1000);
  35. }catch(InterruptedException e){
  36. e.printStackTrace();
  37. }
  38. count++;
  39. }
  40. }
  41. });
  42. thread.start();
  43. }
  44.  
  45. @Override
  46. public boolean onUnbind(Intent intent) {
  47. Log.i(TAG, "Service is Unbinded");
  48. return true;
  49. }
  50.  
  51. @Override
  52. public int onStartCommand(Intent intent, int flags, int startId) {
  53. Log.i(TAG, "Service is started");
  54. return super.onStartCommand(intent, flags, startId);
  55. }
  56.  
  57. @Override
  58. public void onDestroy() {
  59. super.onDestroy();
  60. Log.i(TAG, "Service is Destroyed");
  61. this.quit=true;
  62.  
  63. }
  64.  
  65. @Override
  66. public IBinder onBind(Intent intent) {
  67. Log.i(TAG, "Service is Binded");
  68. return binder;
  69. }
  70. }

  然后使用一个Activity来绑定上面这个Service类,并且声明一个ServiceConnection对象,用于进行数据交互。

  1. package com.example.intentdemo2;
  2.  
  3. import android.app.Activity;
  4. import android.app.Service;
  5. import android.content.ComponentName;
  6. import android.content.Intent;
  7.  
  8. import android.content.ServiceConnection;
  9. import android.os.Bundle;
  10. import android.os.IBinder;
  11. import android.util.Log;
  12. import android.view.View;
  13. import android.widget.Button;
  14. import android.widget.Toast;
  15.  
  16. public class ServiceActivity2 extends Activity {
  17. private final String TAG = "main";
  18. Button bind, unbind, getServiceStatus;
  19. BindService.MyBinder binder;
  20. private ServiceConnection conn = new ServiceConnection() {
  21. @Override
  22. public void onServiceDisconnected(ComponentName name) {
  23. Log.i(TAG, "--Service Disconnected--");
  24. }
  25. @Override
  26. public void onServiceConnected(ComponentName name, IBinder service) {
  27. Log.i(TAG, "--Service Connected--");
  28. // 取得Service对象中的Binder对象
  29. binder = (BindService.MyBinder) service;
  30. }
  31. };
  32.  
  33. @Override
  34. protected void onCreate(Bundle savedInstanceState) {
  35. super.onCreate(savedInstanceState);
  36. setContentView(R.layout.activity_bindservice1);
  37.  
  38. bind = (Button) findViewById(R.id.bind);
  39. unbind = (Button) findViewById(R.id.unbind);
  40. getServiceStatus = (Button) findViewById(R.id.getServiceStatus);
  41.  
  42. final Intent intent = new Intent();
  43. // 指定开启服务的action
  44. intent.setAction("com.bgxt.BindServiceDemo");
  45.  
  46. bind.setOnClickListener(new View.OnClickListener() {
  47.  
  48. @Override
  49. public void onClick(View v) {
  50. // 绑定服务到当前activity中
  51. bindService(intent, conn, Service.BIND_AUTO_CREATE);
  52. }
  53. });
  54. unbind.setOnClickListener(new View.OnClickListener() {
  55.  
  56. @Override
  57. public void onClick(View v) {
  58. // 解除绑定
  59. binder=null;
  60. unbindService(conn);
  61. }
  62. });
  63. getServiceStatus.setOnClickListener(new View.OnClickListener() {
  64.  
  65. @Override
  66. public void onClick(View v) {
  67. if(binder!=null)
  68. {
  69. // 通过绑定服务传递的Binder对象,获取Service暴露出来的数据
  70. Toast.makeText(ServiceActivity2.this,
  71. "Service的Count值为" + binder.getCount(),
  72. Toast.LENGTH_SHORT).show();
  73. Log.i(TAG, "Service的Count值为" + binder.getCount());
  74. }
  75. else
  76. {
  77. Toast.makeText(ServiceActivity2.this,
  78. "还没绑定呢,先绑定。",
  79. Toast.LENGTH_SHORT).show();
  80. }
  81. }
  82. });
  83. }
  84. }

  执行结果,先绑定服务,然后获取当前服务运行时count的值,最后解除绑定,把执行过程输出到LogCat中。

Service的选用

  相信看完以上的内容,对Android下Service组件有了一定的了解,但是对于选用startService()还是使用bindService(),有一些原则需要讲明。如果仅仅是想要启动一个后台服务长期驻留在内存中执行某项任务,那么仅使用startService()启动一个服务即可。但是如果想要与正在运行的服务进行交互,一种方式是使用broadcast,这个以后再介绍,另外一种方式就是使用bindService()绑定一个服务到组件上,使用broadcast的缺点是如果数据交互频繁,容易造成性能上的问题,并且BroadcastReceiver本身执行代码的时间不确定,也许代码执行到一半,后面的代码将不被执行,但是使用bindService()绑定服务即没有这些问题。另外,如果一个服务是依托于某项应用的,那么也最好使用绑定服务,在依托的应用启动的时候绑定服务,这样可以在不使用的时候避免浪费系统资源。

  源码下载

总结

  值得注意的是,Android下的Service组件也是运行在主线程中的,所以一些Android4.0+无法在主线程上进行的操作,在Service中也必须另外开启线程来完成,如访问网络,还可以使用继承Service的子类IntentService来实现,这个内容会在之后的博客中介绍。Android系统本身还提供了大量的Service组件,开发人员可以通过这些系统Service来操作Android系统本身,这不属于本篇博客的范畴,以后再慢慢详解。

Android--Service之基础的更多相关文章

  1. Android Service用法知识点的讲解

    Android Service 学习Service相关知识点: android service 的基础知识,生命周期,service分类,运行地点(本地服务,远程服务),运行类型(前台服务,后台服务) ...

  2. Android Service基础

    Service Service 是一个组件,用来执行长时间的后台操作,不提供用户界面. 另一个应用组件可以启动一个Service,它将持续地在后台运行,即便是用户转移到另一个应用它也不会停止. 另外, ...

  3. Android Service完全解析,关于服务你所需知道的一切(下)

    转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...

  4. Android Content Provider基础

    Android Content Provider基础 Content Providers Content providers管理对一个结构化的数据集合的访问.它们封装了数据,并且提供了保护数据安全性的 ...

  5. Android组件系列----Android Service组件深入解析

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  6. 【转】Android Service完全解析,关于服务你所需知道的一切(下) ---- 不错

    原文网址:http://blog.csdn.net/guolin_blog/article/details/9797169 转载请注册出处:http://blog.csdn.net/guolin_bl ...

  7. Android Service(下)

    转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...

  8. 2017 Android 面试题 [ 基础与细节 ]

    2017 Android 面试题 [ 基础与细节 ] 感谢@chuyao抛出的这些问题,平时业务代码写多了,很多基础的东西变得含糊不清了,这次裸辞出来找工作确实没有之前顺利,顺便求上海Android开 ...

  9. 【Android】详解Android Service

    目录结构: contents structure [+] Service简单概述 Service在清单文件中的声明 Service启动服务 Service绑定服务 扩展Binder类 使用Messen ...

  10. Android Service不能再详细的教程

    这篇包含了: Service后台服务.前台服务.IntentService.跨进程服务.无障碍服务.系统服务 几乎所有Android Service相关的东西. 前言 作为四大组件之一的Service ...

随机推荐

  1. 20155312张竞予 Exp1 PC平台逆向破解(5)M

    Exp1 PC平台逆向破解(5)M 目录 实验内容 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数. 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发get ...

  2. (Swiftmailer)高效的PHP邮件发送库

    Swiftmailer是一个类似PHPMailer邮件发送组件,它也支持HTML格式.附件发送,但它发送效率相当高,成功率也非常高,很多PHP框架都集成了Swiftmailer. Swiftmaile ...

  3. #2019-2020-4 《Java 程序设计》第九周总结

    2019-2020-4 <Java 程序设计>第九周知识总结 第十一章:JDBC与MySQL数据库 11.1 MySQL数据库管理系统 下载安装: 11.2 启动MySQL数据库服务器 具 ...

  4. strchr和strstr 函数

    函数原型:extern char *strchr(char *str,char character) 参数说明:str为一个字符串的指针,character为一个待查找字符.        所在库名: ...

  5. SAS 函数

    SAS 函数 SAS函数是编程语言的一个组件,可接受参数.执行计算或进行其他操作并返回值.返回值是字符型或数值型的结果,可用于赋值语句或 表达式中.SAS包含很多函数,也可以自定义函数.在BASE S ...

  6. 制作DNS字典

    1.收集字典 一般kali自带的DNS爆破工具都会有自己的字典,使用  dpkg -L dns爆破软件名 查询字典的路径.txt文件一般是字典. 合并到一个txt文件中. 2.删除字典中重复的字符串 ...

  7. linux 安装mysql5.7.25

    这两天一直在弄mysql.一直安装.终于可以安装一个成一个了.哈哈哈 自己又写了个脚本希望对大家有所帮助 脚本非常简单 不错操作起来也很容易 重要提示 我的linux 是centos7.不是6. 7和 ...

  8. abaqus的umat在vs中debug调试

    配置参考:https://www.jishulink.com/content/post/333909 常见错误:http://blog.sina.com.cn/s/blog_6116bc050100e ...

  9. python 0228

    01 cpu 内存 硬盘 操作系统 CPU:中央处理器,相当于人大脑. 飞机 内存:临时存储数据. 8g,16g, 高铁 1,成本高. 2,断电即消失. 硬盘:长期存储大量的数据. 1T 512G等等 ...

  10. 第二次scrum

    scrum说明 在第一次已有的基础上,进行了具体的实现.完成了具体的界面设计,还有各个栏目,如:发帖,搜索,禁言等. 类图 依次是外观模式图,发帖图,禁言图. 外观模式图 发帖图 禁言图 团队成员 潘 ...