Service介绍

一、首先,让我们确认下什么是service? 
       service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互、它必须由用户或者其他程序显式的启动、它的优先级比较高,它比处于前台的应用优先级低,但是比后台的其他应用优先级高,这就决定了当系统因为缺少内存而销毁某些没被利用的资源时,它被销毁的概率很小哦。 

二、那么,什么时候,我们需要使用service呢? 
        我们知道,service是运行在后台的应用,对于用户来说失去了被关注的焦点。这就跟我们打开了音乐播放之后,便想去看看图片,这时候我们还不想音乐停止,这里就会用到service;又例如,我们打开了一个下载链接之后,我们肯定不想瞪着眼睛等他下载完再去做别的事情,对吧?这时候如果我们想手机一边在后台下载,一边可以让我去看看新闻啥的,就要用到service。

 
三、service分类: 
       一般我们认为service分为两类,本地service和远程service。 
       本地service顾名思义,那就是和当前应用在同一个进程中的service,彼此之间拥有共同的内存区域,所以对于某些数据的共享特别的方便和简单; 
       远程service:主要牵扯到不同进程间的service访问

StartService和BindService的生命周期

1.   通过startservice开启的服务.一旦服务开启, 这个服务和开启他的调用者之间就没有任何关系了. 调用者不可以访问 service里面的方法. 调用者如果被系统回收了或者调用了ondestroy方法, service还会继续存在。

2.      .通过bindService开启的服务,服务开启之后,调用者和服务之间还存在着联系 , 
一旦调用者挂掉了.service也会跟着挂掉 .

1、整个生命周期

service的整个生命周期是在onCreate()和onDestroy()方法之间。和activity一样,在onCreate()方法里初始化,在onDestroy()方法里释放资源。例如,一个背景音乐播放服务可以在onCreate()方法里播放,在onDestroy()方法里停止。

2、活动的生命周期

service的活动生命周期是在onStartCommand ()之后,这个方法会处理通过startServices()方法传递来的Intent对象。音乐service可以通过开打intent对象来找到要播放的音乐,然后开始后台播放。注:service停止时没有相应的回调方法,即没有onStop()方法,只有onDestroy()销毁方法。

onCreate()方法和onDestroy()方法是针对所有的services,无论它们是否启动,通过Context.startService()和Context.bindService()方法都可以访问执行。然而,只有通过startService()方法启动service服务时才会调用onStartCommand ()方法。

 

 

本地服务(LocalService)和远程服务(RemoteService)的理解

类别

区别

 优点

缺点 

 应用

本地服务(Local)

该服务依附在主进程上,

 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。

 主进程被Kill后,服务便会终止。

 非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务。

远程服务(Remote)

该服务是独立的进程,

 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。

 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。

 一些提供系统服务的Service,这种Service是常驻的。

其实remote服务还是很少见的,并且一般都是系统服务。


其实说白了LocalService就是自己创建的Service,而RemoteService就是别人(别的应用程序)创建的Service

Service与Activity的通信

  • 通过Binder对象

当Activity通过调用bindService(Intentservice, ServiceConnection conn,int flags),我们可以得到一个Service的一个对象实例,然后我们就可以访问Service中的方法,我们还是通过一个例子来理解一下吧,一个模拟下载的小例子,带大家理解一下通过Binder通信的方式

首先我们新建一个工程Communication,然后新建一个Service类

[java] view plaincopy

1. <span style="font-family:System;">package com.example.communication;  
2. 
3. import android.app.Service;  
4. import android.content.Intent;  
5. import android.os.Binder;  
6. import android.os.IBinder;  
7. 
8. public class MsgService extends Service {  
9.     /**
10.      * 进度条的最大值
11.      */
12.     public static final int MAX_PROGRESS = 100;  
13.     /**
14.      * 进度条的进度值
15.      */
16.     private int progress = 0;  
17. 
18.     /**
19.      * 增加get()方法,供Activity调用
20.      * @return 下载进度
21.      */
22.     public int getProgress() {  
23.         return progress;  
24. 
25. 
26.     /**
27.      * 模拟下载任务,每秒钟更新一次
28.      */
29.     public void startDownLoad(){  
30.         new Thread(new Runnable() {  
31. 
32.             @Override
33.             public void run() {  
34.                 while(progress < MAX_PROGRESS){  
35.                     progress += 5;  
36.                     try {  
37.                         Thread.sleep(1000);  
38.                     } catch (InterruptedException e) {  
39. 
40. 
41. 
42. 
43. 
44. 
45. 
46. 
47. 
48.     /**
49.      * 返回一个Binder对象
50.      */
51.     @Override
52.     public IBinder onBind(Intent intent) {  
53.         return new MsgBinder();  
54. 
55. 
56.     public class MsgBinder extends Binder{  
57.         /**
58.          * 获取当前Service的实例
59.          * @return
60.          */
61.         public MsgService getService(){  
62.             return MsgService.this;  
63. 
64. 
65. 
66. }</span>


上面的代码比较简单,注释也比较详细,最基本的Service的应用了,相信你看得懂的,我们调用startDownLoad()方法来模拟下载任务,然后每秒更新一次进度,但这是在后台进行中,我们是看不到的,所以有时候我们需要他能在前台显示下载的进度问题,所以我们接下来就用到Activity了

[java] view plaincopy


1. Intent intent = new Intent("com.example.communication.MSG_ACTION");    
2. bindService(intent, conn, Context.BIND_AUTO_CREATE);


通过上面的代码我们就在Activity绑定了一个Service,上面需要一个ServiceConnection对象,它是一个接口,我们这里使用了匿名内部类

[java] view plaincopy

1. <span style="font-family:System;">  ServiceConnection conn = new ServiceConnection() {  
2. 
3.         @Override
4.         public void onServiceDisconnected(ComponentName name) {  
5. 
6. 
7. 
8.         @Override
9.         public void onServiceConnected(ComponentName name, IBinder service) {  
10.             //返回一个MsgService对象
11. 
12. 
13. 
14.


在onServiceConnected(ComponentName name, IBinder service) 回调方法中,返回了一个MsgService中的Binder对象,我们可以通过getService()方法来得到一个MsgService对象,然后可以调用MsgService中的一些方法,Activity的代码如下

[java] view plaincopy


1. <span style="font-family:System;">package com.example.communication;  
2. 
3. import android.app.Activity;  
4. import android.content.ComponentName;  
5. import android.content.Context;  
6. import android.content.Intent;  
7. import android.content.ServiceConnection;  
8. import android.os.Bundle;  
9. import android.os.IBinder;  
10. import android.view.View;  
11. import android.view.View.OnClickListener;  
12. import android.widget.Button;  
13. import android.widget.ProgressBar;  
14. 
15. public class MainActivity extends Activity {  
16.     private MsgService msgService;  
17.     private int progress = 0;  
18.     private ProgressBar mProgressBar;  
19. 
20. 
21.     @Override
22.     protected void onCreate(Bundle savedInstanceState) {  
23.         super.onCreate(savedInstanceState);  
24. 
25. 
26. 
27.         //绑定Service
28.         Intent intent = new Intent("com.example.communication.MSG_ACTION");  
29. 
30. 
31. 
32. 
33. 
34.         mButton.setOnClickListener(new OnClickListener() {  
35. 
36.             @Override
37.             public void onClick(View v) {  
38.                 //开始下载
39. 
40.                 //监听进度
41. 
42. 
43. 
44. 
45. 
46. 
47. 
48.     /**
49.      * 监听进度,每秒钟获取调用MsgService的getProgress()方法来获取进度,更新UI
50.      */
51.     public void listenProgress(){  
52.         new Thread(new Runnable() {  
53. 
54.             @Override
55.             public void run() {  
56.                 while(progress < MsgService.MAX_PROGRESS){  
57. 
58. 
59.                     try {  
60.                         Thread.sleep(1000);  
61.                     } catch (InterruptedException e) {  
62. 
63. 
64. 
65. 
66. 
67. 
68. 
69. 
70.     ServiceConnection conn = new ServiceConnection() {  
71.         @Override
72.         public void onServiceDisconnected(ComponentName name) {  
73. 
74. 
75. 
76.         @Override
77.         public void onServiceConnected(ComponentName name, IBinder service) {  
78.             //返回一个MsgService对象
79. 
80. 
81. 
82. 
83. 
84.     @Override
85.     protected void onDestroy() {  
86. 
87.         super.onDestroy();  
88. 
89. 
90. 
91. }</span><span style="font-family: simsun;">  
92. </span>


其实上面的代码我还是有点疑问,就是监听进度变化的那个方法我是直接在线程中更新UI的,不是说不能在其他线程更新UI操作吗,可能是ProgressBar比较特殊吧,我也没去研究它的源码,知道的朋友可以告诉我一声,谢谢!

上面的代码就完成了在Service更新UI的操作,可是你发现了没有,我们每次都要主动调用getProgress()来获取进度值,然后隔一秒在调用一次getProgress()方法,你会不会觉得很被动呢?可不可以有一种方法当Service中进度发生变化主动通知Activity,答案是肯定的,我们可以利用回调接口实现Service的主动通知,不理解回调方法的可以看看javascript:void(0)

新建一个回调接口

[java] view plaincopy

1. public interface OnProgressListener {  
2.     void onProgress(int progress);  
3. }

MsgService的代码有一些小小的改变,为了方便大家看懂,我还是将所有代码贴出来

[java] view plaincopy


1. <span style="font-family:System;">package com.example.communication;  
2. 
3. import android.app.Service;  
4. import android.content.Intent;  
5. import android.os.Binder;  
6. import android.os.IBinder;  
7. 
8. public class MsgService extends Service {  
9.     /**
10.      * 进度条的最大值
11.      */
12.     public static final int MAX_PROGRESS = 100;  
13.     /**
14.      * 进度条的进度值
15.      */
16.     private int progress = 0;  
17. 
18.     /**
19.      * 更新进度的回调接口
20.      */
21.     private OnProgressListener onProgressListener;  
22. 
23. 
24.     /**
25.      * 注册回调接口的方法,供外部调用
26.      * @param onProgressListener
27.      */
28.     public void setOnProgressListener(OnProgressListener onProgressListener) {  
29.         this.onProgressListener = onProgressListener;  
30. 
31. 
32.     /**
33.      * 增加get()方法,供Activity调用
34.      * @return 下载进度
35.      */
36.     public int getProgress() {  
37.         return progress;  
38. 
39. 
40.     /**
41.      * 模拟下载任务,每秒钟更新一次
42.      */
43.     public void startDownLoad(){  
44.         new Thread(new Runnable() {  
45. 
46.             @Override
47.             public void run() {  
48.                 while(progress < MAX_PROGRESS){  
49.                     progress += 5;  
50. 
51.                     //进度发生变化通知调用方
52.                     if(onProgressListener != null){  
53. 
54. 
55. 
56.                     try {  
57.                         Thread.sleep(1000);  
58.                     } catch (InterruptedException e) {  
59. 
60. 
61. 
62. 
63. 
64. 
65. 
66. 
67. 
68.     /**
69.      * 返回一个Binder对象
70.      */
71.     @Override
72.     public IBinder onBind(Intent intent) {  
73.         return new MsgBinder();  
74. 
75. 
76.     public class MsgBinder extends Binder{  
77.         /**
78.          * 获取当前Service的实例
79.          * @return
80.          */
81.         public MsgService getService(){  
82.             return MsgService.this;  
83. 
84. 
85. 
86. }</span>


Activity中的代码如下

[java] view plaincopy


1. <span style="font-family:System;">package com.example.communication;  
2. 
3. import android.app.Activity;  
4. import android.content.ComponentName;  
5. import android.content.Context;  
6. import android.content.Intent;  
7. import android.content.ServiceConnection;  
8. import android.os.Bundle;  
9. import android.os.IBinder;  
10. import android.view.View;  
11. import android.view.View.OnClickListener;  
12. import android.widget.Button;  
13. import android.widget.ProgressBar;  
14. 
15. public class MainActivity extends Activity {  
16.     private MsgService msgService;  
17.     private ProgressBar mProgressBar;  
18. 
19. 
20.     @Override
21.     protected void onCreate(Bundle savedInstanceState) {  
22.         super.onCreate(savedInstanceState);  
23. 
24. 
25. 
26.         //绑定Service
27.         Intent intent = new Intent("com.example.communication.MSG_ACTION");  
28. 
29. 
30. 
31. 
32. 
33.         mButton.setOnClickListener(new OnClickListener() {  
34. 
35.             @Override
36.             public void onClick(View v) {  
37.                 //开始下载
38. 
39. 
40. 
41. 
42. 
43. 
44. 
45.     ServiceConnection conn = new ServiceConnection() {  
46.         @Override
47.         public void onServiceDisconnected(ComponentName name) {  
48. 
49. 
50. 
51.         @Override
52.         public void onServiceConnected(ComponentName name, IBinder service) {  
53.             //返回一个MsgService对象
54. 
55. 
56.             //注册回调接口来接收下载进度的变化
57.             msgService.setOnProgressListener(new OnProgressListener() {  
58. 
59.                 @Override
60.                 public void onProgress(int progress) {  
61. 
62. 
63. 
64. 
65. 
66. 
67. 
68. 
69.     @Override
70.     protected void onDestroy() {  
71. 
72.         super.onDestroy();  
73. 
74. 
75. 
76. }  
77. </span>


用回调接口是不是更加的方便呢,当进度发生变化的时候Service主动通知Activity,Activity就可以更新UI操作了

当我们的进度发生变化的时候我们发送一条广播,然后在Activity的注册广播接收器,接收到广播之后更新ProgressBar,代码如下

[java] view plaincopy


1. package com.example.communication;  
2. <span style="font-family:System;">  
3. import android.app.Activity;  
4. import android.content.BroadcastReceiver;  
5. import android.content.Context;  
6. import android.content.Intent;  
7. import android.content.IntentFilter;  
8. import android.os.Bundle;  
9. import android.view.View;  
10. import android.view.View.OnClickListener;  
11. import android.widget.Button;  
12. import android.widget.ProgressBar;  
13. 
14. public class MainActivity extends Activity {  
15.     private ProgressBar mProgressBar;  
16.     private Intent mIntent;  
17.     private MsgReceiver msgReceiver;  
18. 
19. 
20.     @Override
21.     protected void onCreate(Bundle savedInstanceState) {  
22.         super.onCreate(savedInstanceState);  
23. 
24. 
25.         //动态注册广播接收器
26.         msgReceiver = new MsgReceiver();  
27.         IntentFilter intentFilter = new IntentFilter();  
28.         intentFilter.addAction("com.example.communication.RECEIVER");  
29. 
30. 
31. 
32. 
33. 
34.         mButton.setOnClickListener(new OnClickListener() {  
35. 
36.             @Override
37.             public void onClick(View v) {  
38.                 //启动服务
39.                 mIntent = new Intent("com.example.communication.MSG_ACTION");  
40. 
41. 
42. 
43. 
44. 
45. 
46. 
47.     @Override
48.     protected void onDestroy() {  
49.         //停止服务
50. 
51.         //注销广播
52. 
53.         super.onDestroy();  
54. 
55. 
56. 
57.     /**
58.      * 广播接收器
59.      * @author len
60.      *
61.      */
62.     public class MsgReceiver extends BroadcastReceiver{  
63. 
64.         @Override
65.         public void onReceive(Context context, Intent intent) {  
66.             //拿到进度,更新UI
67.             int progress = intent.getIntExtra("progress", 0);  
68. 
69. 
70. 
71. 
72. 
73. }  
74. </span>



[java] view plaincopy


1. <span style="font-family:System;">package com.example.communication;  
2. 
3. import android.app.Service;  
4. import android.content.Intent;  
5. import android.os.IBinder;  
6. 
7. public class MsgService extends Service {  
8.     /**
9.      * 进度条的最大值
10.      */
11.     public static final int MAX_PROGRESS = 100;  
12.     /**
13.      * 进度条的进度值
14.      */
15.     private int progress = 0;  
16. 
17.     private Intent intent = new Intent("com.example.communication.RECEIVER");  
18. 
19. 
20.     /**
21.      * 模拟下载任务,每秒钟更新一次
22.      */
23.     public void startDownLoad(){  
24.         new Thread(new Runnable() {  
25. 
26.             @Override
27.             public void run() {  
28.                 while(progress < MAX_PROGRESS){  
29.                     progress += 5;  
30. 
31.                     //发送Action为com.example.communication.RECEIVER的广播
32.                     intent.putExtra("progress", progress);  
33. 
34. 
35.                     try {  
36.                         Thread.sleep(1000);  
37.                     } catch (InterruptedException e) {  
38. 
39. 
40. 
41. 
42. 
43. 
44. 
45. 
46. 
47. 
48.     @Override
49.     public int onStartCommand(Intent intent, int flags, int startId) {  
50. 
51.         return super.onStartCommand(intent, flags, startId);  
52. 
53. 
54. 
55. 
56.     @Override
57.     public IBinder onBind(Intent intent) {  
58.         return null;  
59. 
60. 
61. 
62. }</span>


总结:

  1. Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法
  2.  Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好