一、 Service简单介绍

Service是android 系统中的四大组件之中的一个(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差点儿相同,但不能自己执行仅仅能后台执行,而且能够和其它组件进行交互。service能够在非常多场合的应用中使用,比方播放多媒体的时候用户启动了其它Activity这个时候程序要在后台继续播放,比方检測SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的。

Service的启动有两种方式:context.startService() 和 context.bindService()

二、 Service启动流程

context.startService() 启动流程:

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

startService(new Intent(LoginActivity.this, XXService.class));

假设Service还没有执行,则android先调用onCreate(),然后调用onStart();

假设Service已经执行,则仅仅调用onStart(),所以一个Service的onStart方法可能会反复调用多次。

假设stopService的时候会直接onDestroy,假设是调用者自己直接退出而没有调用stopService的话,Service会一直在后台执行,该Service的调用者再启动起来后能够通过stopService关闭Service。

所以调用startService的生命周期为:onCreate --> onStart (可多次调用)
--> onDestroy

context.bindService()启动流程:

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

在Service每一次的开启关闭过程中,仅仅有onStart可被多次调用(通过多次startService调用),其它onCreate,onBind,onUnbind,onDestory在一个生命周期中仅仅能被调用一次。

onBind()将返回给client一个IBind接口实例,IBind同意client回调服务的方法,比方得到Service的实例、执行状态或其它操作。这个时候把调用者(Context,比如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy对应退出。

所以调用bindService的生命周期为:onCreate --> onBind(仅仅一次,不可多次绑定) --> onUnbind --> onDestory。

三、 Service生命周期 

Service的生命周期并不像Activity那么复杂,它仅仅继承了onCreate()、onStart()、onDestroy()三个方法

当我们第一次启动Service时,先后调用了onCreate()、onStart()这两个方法;当停止Service时,则运行onDestroy()方法。

这里须要注意的是,假设Service已经启动了,当我们再次启动Service时,不会在运行onCreate()方法,而是直接运行onStart()方法。

它能够通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己,仅仅要调用一次stopService()方法便能够停止服务,不管调用了多少次的启动服务方法。

四、 Service演示样例

以下我做了一个简单的音乐播放的应用,分别使用startService和bindService来启动本地的服务。

Activity

  1. public class PlayMusicService extends Activity implements OnClickListener {
  2. private Button playBtn;
  3. private Button stopBtn;
  4. private Button pauseBtn;
  5. private Button exitBtn;
  6. private Button closeBtn;
  7. private Intent intent;
  8. @Override
  9. public void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.music_service);
  12. playBtn = (Button) findViewById(R.id.play);
  13. stopBtn = (Button) findViewById(R.id.stop);
  14. pauseBtn = (Button) findViewById(R.id.pause);
  15. exitBtn = (Button) findViewById(R.id.exit);
  16. closeBtn = (Button) findViewById(R.id.close);
  17. playBtn.setOnClickListener(this);
  18. stopBtn.setOnClickListener(this);
  19. pauseBtn.setOnClickListener(this);
  20. exitBtn.setOnClickListener(this);
  21. closeBtn.setOnClickListener(this);
  22. }
  23. @Override
  24. public void onClick(View v) {
  25. int op = -1;
  26. intent = new Intent("com.homer.service.musicService");
  27. switch (v.getId()) {
  28. case R.id.play:                             // play music
  29. op = 1;
  30. break;
  31. case R.id.stop:                             // stop music
  32. op = 2;
  33. break;
  34. case R.id.pause:                            // pause music
  35. op = 3;
  36. break;
  37. case R.id.close:                            // close activity
  38. this.finish();
  39. break;
  40. case R.id.exit:                             // stopService
  41. op = 4;
  42. stopService(intent);
  43. this.finish();
  44. break;
  45. }
  46. Bundle bundle = new Bundle();
  47. bundle.putInt("op", op);
  48. intent.putExtras(bundle);
  49. startService(intent);                           // startService
  50. }
  51. @Override
  52. public void onDestroy(){
  53. super.onDestroy();
  54. if(intent != null){
  55. stopService(intent);
  56. }
  57. }
  58. }

Service

  1. public class MusicService extends Service {
  2. private static final String TAG = "MyService";
  3. private MediaPlayer mediaPlayer;
  4. @Override
  5. public IBinder onBind(Intent arg0) {
  6. return null;
  7. }
  8. @Override
  9. public void onCreate() {
  10. Log.v(TAG, "onCreate");
  11. Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();
  12. if (mediaPlayer == null) {
  13. mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
  14. mediaPlayer.setLooping(false);
  15. }
  16. }
  17. @Override
  18. public void onDestroy() {
  19. Log.v(TAG, "onDestroy");
  20. Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);
  21. if (mediaPlayer != null) {
  22. mediaPlayer.stop();
  23. mediaPlayer.release();
  24. }
  25. }
  26. @Override
  27. public void onStart(Intent intent, int startId) {
  28. Log.v(TAG, "onStart");
  29. if (intent != null) {
  30. Bundle bundle = intent.getExtras();
  31. if (bundle != null) {
  32. int op = bundle.getInt("op");
  33. switch (op) {
  34. case 1:
  35. play();
  36. break;
  37. case 2:
  38. stop();
  39. break;
  40. case 3:
  41. pause();
  42. break;
  43. }
  44. }
  45. }
  46. }
  47. public void play() {
  48. if (!mediaPlayer.isPlaying()) {
  49. mediaPlayer.start();
  50. }
  51. }
  52. public void pause() {
  53. if (mediaPlayer != null && mediaPlayer.isPlaying()) {
  54. mediaPlayer.pause();
  55. }
  56. }
  57. public void stop() {
  58. if (mediaPlayer != null) {
  59. mediaPlayer.stop();
  60. try {
  61. mediaPlayer.prepare();  // 在调用stop后假设须要再次通过start进行播放,须要之前调用prepare函数
  62. } catch (IOException ex) {
  63. ex.printStackTrace();
  64. }
  65. }
  66. }
  67. }

AndroidManifest.xml

注冊activity

  1. <activity
  2. android:name=".service.PlayMusicService"
  3. android:label="@string/app_name" />

注冊service

  1. <service
  2. android:name=".service.MusicService"
  3. android:enabled="true" >
  4. <intent-filter>
  5. <action android:name="com.homer.service.musicService" />
  6. </intent-filter>
  7. </service>

五、 代码解析

1、Activity中,PlayMusicService中通过重写OnClickListener 接口onClick()方法实现对播放音乐的控制,把音乐各种操作用数字通过Intent传递给service

然后通过构造一个Intent , intent = new Intent("com.homer.service.musicService");

当中,com.homer.service.musicService是 AndroidManifest.xml 对service的定义,即上面“注冊service”

2、Activity中,音乐播放的控制,利用Bundle绑定数字op后,通过 startService(intent); 服务后发送出去

Bundle bundle = new Bundle();

bundle.putInt("op", op);

intent.putExtras(bundle);

startService(intent);

3、 Service中,会处理Activity启动的 startService(intent);服务,依次调用service的启动过程:onCreate --> onStart(可多次调用) --> onDestroy

onCreate(),  创建mediaPlayer

onStart(),      通过获取Bundle bundle = intent.getExtras();,提取int op = bundle.getInt("op");,然后运行响应的音乐播放操作

onDestroy(),停止并释放mediaPlayer音乐资源,假设当运行context.stopService()时调用此方法

4、Activity中,onClick()函数中close与exit是运行含义是不同的:

close : 仅仅是运行了this.finish(); 关闭了本Activity窗口,service并没有被关掉,音乐依旧会继续在后台播放

exit  : 先调用了stopService(intent); 关闭了service服务,在Service中会调用3中的onDestroy()停止并释放音乐资源,后才运行this.finish(); 关闭了本Activity窗口

源代码下载

六、 拓展知识(进程和声明周期)

Android操作系统尝试尽可能长时间的保持应用的进程,但当可用内存非常低时终于要移走一部分进程。如何确定那些程序能够执行,那些要被销毁,Android让每个进程在一个重要级的基础上执行,重要级低的进程最有可能被淘汰,一共同拥有5级,以下这个列表就是依照重要性排列的:

1 一个前台进程显示的是用户此时须要处理和显示的。下列的条件有不论什么一个成立,这个进程都被觉得是在前台执行的。

        a 与用户正发生交互的。

        b 它控制一个与用户交互的必须的主要的服务。

        c 有一个正在调用生命周期的回调函数的service(如onCreate()、onStar()、onDestroy())

        d 它有一个正在执行onReceive()方法的广播接收对象。

仅仅有少数的前台进程可以在不论什么给定的时间内执行,销毁他们是系统万不得已的、最后的选择——当内存不够系统继续执行下去时。通常,在这一点上,设备已经达到了内存分页状态,所以杀掉一些前台进程来保证可以响应用户的需求。

2 一个可用进程没有不论什么前台组件,但它仍然能够影响到用户的界面。以下两种情况发生时,能够称该进程为可用进程。

        它是一个非前台的activity,但对用户仍然可用(onPause()方法已经被调用)这是可能发生的,比如:前台的activity是一个同意上一个activity可见的对话框,即当前activity半透明,能看到前一个activity的界面,它是一个服务于可用activity的服务。



3 一个服务进程是一个通过调用startService()方法启动的服务,而且不属于前两种情况。虽然服务进程没有直接被用户看到,但他们确实是用户所关心的,比方后台播放音乐或网络下载数据。所以系统保证他们的执行,直到不能保证全部的前台可见程序都正常执行时才会终止他们。



4 一个后台进程就是一个非当前正在执行的activity(activity的onStop()方法已经被调用),他们不会对用户体验造成直接的影响,当没有足够内存来执行前台可见程序时,他们将会被终止。通常,后台进程会有非常多个在执行,所以他们维护一个LRU近期使用程序列表来保证常常执行的activity能最后一个被终止。假设一个activity正确的实现了生命周期的方法,而且保存它当前状态,杀死这些进程将不会影响到用户体验。



5 一个空线程没有执行不论什么可用应用程序组,保留他们的唯一原因是为了设立一个缓存机制,来加快组件启动的时间。系统常常杀死这些内存来平衡系统的整个系统的资源,进程缓存和基本核心缓存之间的资源。

Android把进程里优先级最高的activity或服务,作为这个进程的优先级。比如,一个进程拥有一个服务和一个可见的activity,那么这个进程将会被定义为可见进程,而不是服务进程。



此外,假设别的进程依赖某一个进程的话,那么被依赖的进程会提高优先级。一个进程服务于还有一个进程,那么提供服务的进程不会低于获得服务的进程。比如,假设进程A的一个内容提供商服务于进程B的一个client,或者进程A的一个service被进程B的一个组件绑定,那么进程A至少拥有和进程B一样的优先级,或者更高。



由于一个执行服务的进程的优先级高于执行后台activity的进程,一个activity会准备一个长时间执行的操作来启动一个服务,而不是启动一个线程–尤其是这个操作可能会拖垮这个activity。比如后台播放音乐的同一时候,通过照相机向server发送一张照片,启动一个服务会保证这个操作至少执行在service 进程的优先级下,不管这个activity发生了什么,广播接收者应该作为一个空服务而不是简单的把耗时的操作单独放在一个线程里。

android关键组件service服务(一)的更多相关文章

  1. Android 四大组件 Service 服务

    1.Service简单介绍 依照使用范围分类: 类别 优点 缺点 差别 应用 本地服务 Local  Service 本地服务在一定程度上节约了资源,另外本地服务由于是在同一进程,因此不须要IPC,也 ...

  2. Android 学习笔记 Service服务与远程通信...(AIDL)

    PS:这一章节看的我有几分迷茫,不是很容易理解...不过还好总算是明白了一大半了...基本的迷惑是解决了... 学习内容: 1.跨应用启动服务... 2.跨应用绑定服务... 3.跨应用实现通信... ...

  3. Android四大组件——Service

    Service相关链接 Service初涉 Service进阶 Service精通 Service是Android系统中的一种组件,它跟Activity的级别差不多,但是它不能自己运行,只能后台运行, ...

  4. Android四大组件-Service

    http://blog.csdn.net/guolin_blog/article/details/11952435 http://www.jianshu.com/p/eeb2bd59853f 概述 定 ...

  5. Android四大组件之服务的两种启动方式详解

    Service简单概述 Service(服务):是一个没有用户界面.可以在后台长期运行且可以执行操作的应用组件.服务可由其他应用组件启动(如:Activity.另一个service).此外,组件可以绑 ...

  6. Android四大组件之服务-Service 原理和应用开发详解

    一.Android 服务简介 Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver.ContentProvider),它跟Acti ...

  7. Android开发学习—— Service 服务

    Service运行于后台的一个组件,用来运行适合运行在后台的代码,服务是没有前台界面,可以视为没有界面的activity. 服务可以被手动关闭,不会重启,但是如果被自动关闭,内存充足就会重启. sta ...

  8. Android四大组件之服务

    创建一个服务,并与活动绑定 作为安卓四大组件之一的服务,毫无例外也要在manifast中进行注册 新建服务类继承于Service,并覆盖onBind( )方法,用于与活动绑定 public class ...

  9. Android 综合揭秘 —— 全面剖释 Service 服务

    引言 Service 服务是 Android 系统最常用的四大部件之一,Android 支持 Service 服务的原因主要目的有两个,一是简化后台任务的实现,二是实现在同一台设备当中跨进程的远程信息 ...

随机推荐

  1. AWK的介绍学习

    第一节.awk的工作流程和基本用法 1.awk介绍 awk是一种报表生成器,就是对文件进行格式化处理的,这里的格式化不是文件系统的格式化,而是对文件内容进行各种"排版",进而格式化 ...

  2. Linux 常用命令:系统状态篇

    前言 Linux常用命令中,有些命令可以用于查看系统的状态,通过了解系统当前的状态,能够帮助我们更好地维护系统或定位问题.本文就简单介绍一下这些命令. 1. 查看系统运行时间--uptime 有时候我 ...

  3. xargs---组合命令的工具

    xargs命令是给其他命令传递参数的一个过滤器,也是组合多个命令的一个工具.它擅长将标准输入数据转换成命令行参数,xargs能够处理管道或者stdin并将其转换成特定命令的命令参数.xargs也可以将 ...

  4. python之禅---对象与元类

    众所周知,python是一门面向对象的编程语言,python中一切皆对象,那么我们先探讨一下什么是对象. 一.对象 在生活中一个事物就是一个对象,比如:一只猫就是一个对象,猫的体型.猫毛的颜色等是它的 ...

  5. Unity 如何将apk放到Android系统的system里

    有时我们需要用unity开发一款Android的系统软件,很坑,步骤如下: 1.用unity打包出来,签名. 2.用解压工具打开签过名的apk. 3.将lib里面的.so文件复制出来. 4.adb r ...

  6. 网络编程select函数

    select函数的作用: 在编程的过程中,经常会遇到许多阻塞的函数,好像read和网络编程时使用的recv, recvfrom函数都是阻塞的函数,当函数不能成功执行的时候,程序就会一直阻塞在这里,无法 ...

  7. 【转】 HtmlAgilityPack使用——XPath注意事项

    [转] HtmlAgilityPack使用——XPath注意事项 在使用HtmlAgilityPack这个开源的类库进行网页内容解析的时候是非常的方便(使用方法见另一篇博客<HTML解析:基于X ...

  8. Qt之图形(绘制文本)

    简述 前面我们讲解了Qt图形的基本绘制,其中包括: 绘制文本.直线.直线.矩形.弧线.椭圆.多边形.图片,以及其它一些高级用法,比如:渐变.转换等. 本节我们来详细讲解文字的绘制.主要通过QPaint ...

  9. js实现复选框的操作-------Day41

    不知道之前的一篇为什么一直处于审核阶段.难道有哪个词语是敏感词被河蟹了? 无论了,又一次写了这篇,也算是加深记忆吧. 首先要写的是今天在进行表格数据操作时用到的对复选框checkbox的全选和全不选, ...

  10. 使用ssh过程中对数据库进行update时报错

    报错信息:org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in ...