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操作了
- 通过broadcast(广播)的形式
当我们的进度发生变化的时候我们发送一条广播,然后在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>
总结:
- Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法
- Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好