Android 中的 Service 全面总结

  1. @Override

  2. public IBinder onBind(Intent intent) {

  3. return null;

  4. }

  5. @Override

  6. public void onCreate() {

  7. super.onCreate();

  8. }

  9. @Override

  10. public void onStart(Intent intent, int startId) {

  11. super.onStart(intent, startId);

  12. }

  13. @Override

  14. public void onDestroy() {

  15. super.onDestroy();

  16. }

  17. }

对应生命周期系统回调函数上面已经说明,在对应地方加上适当的代码即可。下面是启动与停止 Se r vice 的代码:

[java] view plain copy

  1. // 启动一个 Activity

  2. startService(new Intent(this, LocalService1.class));

  3. // 停止一个 Activity

  4. stopService(new Intent(this, LocalService1.class));

对应的 Intent 为标志服务类的 Intent。

5、Local 与 Remote 服务绑定

同样记得在 Androidmanifest.xml 中注册 service

1). Local 服务绑定:Local 服务的绑定较简单,首先在 Service 中我们需要实现 Service 的抽象方法 onBind,并返回一个实现 IBinder 接口的对象。

Service 中的代码:

[java] view plain copy

  1. package com.newcj.test;

  2. import android.app.Service;

  3. import android.content.Intent;

  4. import android.os.Binder;

  5. import android.os.IBinder;

  6. public class LocalService extends Service {

  7. /**

  8. * 在 Local Service 中我们直接继承 Binder 而不是 IBinder,因为 Binder 实现了 IBinder 接口,这样我们可以少做很多工作。

  9. * @author newcj

  10. */

  11. public class SimpleBinder extends Binder{

  12. /**

  13. * 获取 Service 实例

  14. * @return

  15. */

  16. public LocalService getService(){

  17. return LocalService.this;

  18. }

  19. public int add(int a, int b){

  20. return a + b;

  21. }

  22. }

  23. public SimpleBinder sBinder;

  24. @Override

  25. public void onCreate() {

  26. super.onCreate();

  27. // 创建 SimpleBinder

  28. sBinder = new SimpleBinder();

  29. }

  30. @Override

  31. public IBinder onBind(Intent intent) {

  32. // 返回 SimpleBinder 对象

  33. return sBinder;

  34. }

  35. }

上面的代码关键之处,在于 onBind(Intent) 这个方法 返回了一个实现了 IBinde r  接口的对象,这个对象将用于绑定Se r vice 的 Activity 与 Local Se r vice 通信。下面是 Activity 中的代码:

[java] view plain copy

  1. package com.newcj.test;

  2. import android.app.Activity;

  3. import android.content.ComponentName;

  4. import android.content.Context;

  5. import android.content.Intent;

  6. import android.content.ServiceConnection;

  7. import android.os.Bundle;

  8. import android.os.IBinder;

  9. import android.util.Log;

  10. import android.view.View;

  11. import android.view.View.OnClickListener;

  12. public class Main extends Activity {

  13. private final static String TAG = “SERVICE_TEST”;

  14. private ServiceConnection sc;

  15. private boolean isBind;

  16. @Override

  17. public void onCreate(Bundle savedInstanceState) {

  18. super.onCreate(savedInstanceState);

  19. setContentView(R.layout.main);

  20. sc = new ServiceConnection() {

  21. @Override

  22. public void onServiceDisconnected(ComponentName name) {

  23. }

  24. @Override

  25. public void onServiceConnected(ComponentName name, IBinder service) {

  26. LocalService.SimpleBinder sBinder = (LocalService.SimpleBinder)service;

  27. Log.v(TAG, "3 + 5 = " + sBinder.add(3, 5));

  28. Log.v(TAG, sBinder.getService().toString());

  29. }

  30. };

  31. findViewById(R.id.btnBind).setOnClickListener(new OnClickListener() {

  32. @Override

  33. public void onClick(View v) {

  34. bindService(new Intent(Main.this, LocalService.class), sc, Context.BIND_AUTO_CREATE);

  35. isBind = true;

  36. }

  37. });

  38. findViewById(R.id.btnUnbind).setOnClickListener(new OnClickListener() {

  39. @Override

  40. public void onClick(View v) {

  41. if(isBind){

  42. unbindService(sc);

  43. isBind = false;

  44. }

  45. }

  46. });

  47. }

  48. }

在 Activity 中,我们通过 ServiceConnection 接口来取得建立连接 与 连接意外丢失的回调。bindService有三个参数,第一个是用于区分 Service 的Intent 与 startService 中的 Intent 一致,第二个是实现了 ServiceConnection 接口的对象,最后一个是 flag 标志位。有两个flag,BIND_DEBUG_UNBIND 与 BIND_AUTO_CREATE,前者用于调试(详细内容可以查看javadoc 上面描述的很清楚),后者默认使用。unbindService 解除绑定,参数则为之前创建的 ServiceConnection 接口对象。另外,多次调用 unbindService 来释放相同的连接会抛出异常,因此我创建了一个 boolean 变量来判断是否 unbindService 已经被调用过。

运行结果:

2). Remote 服务绑定:Remote 的服务绑定由于服务是在另外一个进程,因此需要用到 android 的 IPC 机制。这将又是一个很长的话题,因此,我打算写另外一篇 android 的 IPC 机制分析 ,并在其中进行详述,然后在这里更新链接,敬请关注。

特别注意:

1、Service.onBind如果返回null,则调用 bindService 会启动 Service,但不会连接上 Service,因此 ServiceConnection.onServiceConnected 不会被调用,但你任然需要使用 unbindService 函数断开它,这样 Service 才会停止。

6、创建前台服务

前台服务的优点上面已经说明,但设置服务为前台服务,我们需要注意在 sdk 2.0 及其以后版本使用的方法是 startForeground 与 stopForeground,之前版本使用的是 setForeground ,因此如果你应用程序的最低运行环境要求是 2.0,那么这里可以直接运用新方法,如果运行环境是2.0以下,那么为了保证向后兼容性,这里必须使用反射技术来调用新方法。

下面是我仿照 ApiDemos 重新敲的代码,对某些地方进行了修改,因此更具有说明性:

在 Activity 中,我们通过 ServiceConnection 接口来取得建立连接 与 连接意外丢失的回调。bindService有三个参数,第一个是用于区分 Service 的Intent 与 startService 中的 Intent 一致,第二个是实现了 ServiceConnection 接口的对象,最后一个是 flag 标志位。有两个flag,BIND_DEBUG_UNBIND 与 BIND_AUTO_CREATE,前者用于调试(详细内容可以查看javadoc 上面描述的很清楚),后者默认使用。unbindService 解除绑定,参数则为之前创建的 ServiceConnection 接口对象。另外,多次调用 unbindService 来释放相同的连接会抛出异常,因此我创建了一个 boolean 变量来判断是否 unbindService 已经被调用过。

运行结果:

2). Remote 服务绑定:Remote 的服务绑定由于服务是在另外一个进程,因此需要用到 android 的 IPC 机制。这将又是一个很长的话题,因此,我打算写另外一篇 android 的 IPC 机制分析 ,并在其中进行详述,然后在这里更新链接,敬请关注。

特别注意:

1、Service.onBind如果返回null,则调用 bindService 会启动 Service,但不会连接上 Service,因此 ServiceConnection.onServiceConnected 不会被调用,但你任然需要使用 unbindService 函数断开它,这样 Service 才会停止。

6、创建前台服务

前台服务的优点上面已经说明,但设置服务为前台服务,我们需要注意在 sdk 2.0 及其以后版本使用的方法是 startForeground 与 stopForeground,之前版本使用的是 setForeground ,因此如果你应用程序的最低运行环境要求是 2.0,那么这里可以直接运用新方法,如果运行环境是2.0以下,那么为了保证向后兼容性,这里必须使用反射技术来调用新方法。

下面是我仿照 ApiDemos 重新敲的代码,对某些地方进行了修改,因此更具有说明性:

[java] view plain copy

  1. package com.newcj.test;

  2. import java.lang.reflect.InvocationTargetException;

  3. import java.lang.reflect.Method;

  4. import android.app.Notification;

  5. import android.app.NotificationManager;

  6. import android.app.PendingIntent;

  7. import android.app.Service;

  8. import android.content.Context;

  9. import android.content.Intent;

  10. import android.os.IBinder;

  11. public class ForegroundService extends Service {

  12. private static final Class[] mStartForegroundSignature = new Class[] {

  13. int.class, Notification.class};

  14. private static final Class[] mStopForegroundSignature = new Class[] {

  15. boolean.class};

  16. private NotificationManager mNM;

  17. private Method mStartForeground;

  18. private Method mStopForeground;

  19. private Object[] mStartForegroundArgs = new Object[2];

  20. private Object[] mStopForegroundArgs = new Object[1];

  21. @Override

  22. public IBinder onBind(Intent intent) {

  23. return null;

  24. }

  25. @Override

  26. public void onCreate() {

  27. super.onCreate();

  28. mNM = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

  29. try {

  30. mStartForeground = ForegroundService.class.getMethod(“startForeground”, mStartForegroundSignature);

  31. mStopForeground = ForegroundService.class.getMethod(“stopForeground”, mStopForegroundSignature);

  32. } catch (NoSuchMethodException e) {

  33. mStartForeground = mStopForeground = null;

  34. }

  35. // 我们并不需要为 notification.flags 设置 FLAG_ONGOING_EVENT,因为

  36. // 前台服务的 notification.flags 总是默认包含了那个标志位

  37. Notification notification = new Notification(R.drawable.icon, “Foreground Service Started.”,

  38. System.currentTimeMillis());

  39. PendingIntent contentIntent = PendingIntent.getActivity(this, 0,

  40. new Intent(this, Main.class), 0);

  41. notification.setLatestEventInfo(this, “Foreground Service”,

  42. “Foreground Service Started.”, contentIntent);

  43. // 注意使用  startForeground ,id 为 0 将不会显示 notification

  44. startForegroundCompat(1, notification);

  45. }

  46. @Override

  47. public void onDestroy() {

  48. super.onDestroy();

  49. stopForegroundCompat(1);

  50. }

  51. // 以兼容性方式开始前台服务

  52. private void startForegroundCompat(int id, Notification n){

  53. if(mStartForeground != null){

  54. mStartForegroundArgs[0] = id;

  55. mStartForegroundArgs[1] = n;

  56. try {

  57. mStartForeground.invoke(this, mStartForegroundArgs);

  58. } catch (IllegalArgumentException e) {

  59. e.printStackTrace();

  60. } catch (IllegalAccessException e) {

  61. e.printStackTrace();

  62. } catch (InvocationTargetException e) {

  63. e.printStackTrace();

  64. }

  65. return;

  66. }

  67. setForeground(true);

  68. mNM.notify(id, n);

  69. }

  70. // 以兼容性方式停止前台服务

  71. private void stopForegroundCompat(int id){

  72. if(mStopForeground != null){

  73. mStopForegroundArgs[0] = Boolean.TRUE;

  74. try {

  75. mStopForeground.invoke(this, mStopForegroundArgs);

  76. } catch (IllegalArgumentException e) {

  77. e.printStackTrace();

  78. } catch (IllegalAccessException e) {

  79. e.printStackTrace();

  80. } catch (InvocationTargetException e) {

  81. e.printStackTrace();

  82. }

  83. return;

  84. }

  85. //  在 setForeground 之前调用 cancel,因为我们有可能在取消前台服务之后

  86. //  的那一瞬间被kill掉。这个时候 notification 便永远不会从通知一栏移除

  87. mNM.cancel(id);

  88. setForeground(false);

  89. }

  90. }

特别注意:

1、使用 startForeground ,如果 id 为 0 ,那么 notification 将不会显示。

7、在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService

如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。另外如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。

8、在 AndroidManifest.xml 里 Service 元素的常见选项

android:name  -------------  服务类名

android:label  --------------  服务的名字,如果此项不设置,那么默认显示的服务名则为类名

android:icon  --------------  服务的图标

android:permission  -------  申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务

android:process  ----------  表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字

android:enabled  ----------  如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false

android:exported  ---------  表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

本文代码下载地址:http://files.cnblogs.com/newcj/ServiceTest.zip

会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。

8、在 AndroidManifest.xml 里 Service 元素的常见选项

android:name  -------------  服务类名

android:label  --------------  服务的名字,如果此项不设置,那么默认显示的服务名则为类名

android:icon  --------------  服务的图标

android:permission  -------  申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务

android:process  ----------  表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字

android:enabled  ----------  如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false

android:exported  ---------  表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

本文代码下载地址:http://files.cnblogs.com/newcj/ServiceTest.zip

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值