Bound Service 是客户端-服务器模式的服务,它允许允许组件(比如activity)对其进行绑定、发送请求、接收响应、甚至进行进程间通信(IPC)。为了提供绑定,开发人员必须实现onBind()毁掉方法,该方法返回IBinder对象,它定义了客户端用来与服务交互的程序接口。
客户端通过bindService()方法绑定到服务。此时,客户端必须提供ServiceConnection接口的实现类,它监视客户端和服务之间的连接。多个客户端能够同时连接服务器。然而仅当第一个客户端绑定时,系统调用服务的onBind()方法来获取IBinder对象。然后,系统会向后续请求绑定的客户端传送这同一个 IBinder ,而不再调用 onBind() 。
当最后一个客户端解除绑定后,系统会销毁服务(除非服务同时是通过 startService() 启动的)。
一:创建Bound服务
当你实现自己的bound服务时,最重要的工作就是定义 onBind() 回调方法所返回的接口。 有一下三种方式:
(1)继承Binder类
如果服务是你的应用程序所私有的,并且与客户端运行于同一个进程中(通常都是如此),你应该通过j继承 Binder 类来创建你的接口,并从 onBind() 返回一个它的实例。客户端接收该 Binder 对象并用它来直接访问 Binder 实现类或者 Service 中可用的公共(public)方法。
如果服务只应用于私有应用程序,那这就是首选的技术方案。如果服务要被其它应用程序使用或者访问独立进程时,则不能使用该技术。
仅当客户端与服务位于同一个应用程序和进程时,才可以。例如音乐播放我绑定activity到自己的服务来在后台播放音乐。
实现步骤如下:
- 在你的服务中,创建一个 Binder 的实例,实现以下三者之一:
(1)包含客户端能调用的公共方法
(2)返回当前service实例,其中包含客户端能够调用的公共方法
(3)返回服务管理的其他类的实例,其中包含客户端能够调用的公共方法
- 从回调方法 onBind() 中返回 Binder 类的实例。
- 在客户端中,在回调方法 onServiceConnected() 中接收 Binder 类实例并用所提供的方法对绑定的服务进行调用。
以下是一个服务的示例,它通过实现一个 Binder 来为客户端访问它内部的方法提供支持:
public class LocalService extends Service { // 给客户端的Binder private final IBinder mBinder = new LocalBinder(); // 产生随机数 private final Random mGenerator = new Random(); public class LocalBinder extends Binder { LocalService getService() { // 返回LocalService 的实例,其中包含客户端可以调用的方法 return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } /**客户端可以调用的方法 */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
LocalBinder为客户端提供了getService()方法,用于返回当前LocalService的实例。 这就让客户端可以调用服务中的公共方法。比如,客户端可以调用服务中的getRandomNumber()。
以下是一个绑定到LocalService的activity,当点击按钮时,它会调用getRandomNumber():
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // 绑定到 LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // 解除绑定的服务 if (mBound) { unbindService(mConnection); mBound = false; } } /** 点击Button时,调用此方法 */ public void onButtonClick(View v) { if (mBound) { // 调用LocalService中的方法。 // 不过,如果该调用会导致某些操作的挂起,那么调用应该放入单独的线程中进行, // 以免降低activity的性能。 int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** 定义服务绑定的回调方法,将其传给bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // 我们已经绑定了服务, 将IBinder转型获得LocalService实例 LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }
上述例子展示了客户端如何利用 ServiceConnection 和 onServiceConnected() 回调方法绑定到服务。
(2)使用Messenger类
如果你的服务需要与远程进程进行通信,那你可以使用一个 Messenger 来提供服务的接口。这种技术能让你无需使用AIDL就能进行进程间通信(IPC),这是执行进程间通信(IPC)最为简便的方式。
以下是使用方法:
- 服务实现一个 Handler ,用于客户端每次调用时接收回调。
- 此 Handler 用于创建一个 Messenger 对象(它是一个对 Handler 的引用)。
- 此 Messenger 对象创建一个 IBinder ,服务在 onBind() 中把它返回给客户端。
- 客户端用 IBinder 将 Messenger (引用服务的 Handler )实例化,客户端用它向服务发送消息对象 Message 。
- 服务接收 Handler 中的每个消息 Message ——确切的说,是在 handleMessage() 方法中接收。
通过这种方式,客户端不需要调用服务中的“方法”。取而代之的是,客户端发送“消息”( Message 对象),服务则接收位于 Handler 中的这个消息。
public class MessengerService extends Service { static final int MSG_SAY_HELLO = 1; /** * 服务处理客户端发来的消息 * 服务实现了一个Handler */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * 给客户端使用的用来发送消息给 IncomingHandler.即为,第二步。 */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * 返回一个接口用来给服务发送消息,即为,第三步 */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } }
客户端要做的全部工作就是根据服务返回的 IBinder 创建一个 Messenger ,并用 send() 方法发送一个消息。例如,以下是一个activity示例,它绑定到上述服务,并向服务发送 MSG_SAY_HELLO消息:
public class ActivityMessenger extends Activity { /** 和service沟通的Messenger. */ Messenger mService = null; /** 是否已经绑定 */ boolean mBound; /** * 与服务进行交互 */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // 与服务建立联接后将会调用本方法, // 给出用于和服务交互的对象。 // 我们将用一个Messenger来与服务进行通信, // 因此这里我们获取到一个原始IBinder对象的客户端实例。 mService = new Messenger(service); mBound = true; } public void onServiceDisconnected(ComponentName className) { // 当与服务的联接被意外中断时——也就是说服务的进程崩溃了, // 将会调用本方法。 mService = null; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; // 创建并向服务发送一个消息,用到了已约定的'what'值 Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); //绑定到服务 bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // 解除绑定 if (mBound) { unbindService(mConnection); mBound = false; } } }
二:绑定到服务
应用程序组件(客户端)可以通过调用 bindService() 来绑定服务。然后Android系统会调用服务的 onBind() 方法,返回一个用于和服务进行交互的 IBinder 。
绑定是异步进行的。 bindService() 将立即返回,并不会向客户端返回 IBinder 。为了接收 IBinder ,客户端必须创建一个 ServiceConnection 的实例,并把它传给 bindService() 。 ServiceConnection 包含了一个回调方法,系统将会调用该方法来传递客户端所需的那个 IBinder 。
注意: 只有activity、service和content provider才可以绑定到服务上——broadcast receiver不能绑定服务。
因此,要把客户端绑定到服务上,你必须:
- 实现 ServiceConnection 。你的实现代码必须重写两个回调方法:onServiceConnected()系统调用该方法来传递服务的 onBind() 方法所返回的 IBinder 。onServiceDisconnected()当与服务的联接发生意外中断时,比如服务崩溃或者被杀死时,Android系统将会调用该方法。客户端解除绑定时,不会调用该方法。
- 调用 bindService() ,传入已实现的 ServiceConnection 。
- 当系统调用你的 onServiceConnected() 回调方法时,你可以利用接口中定义的方法开始对服务的调用。
- 要断开与服务的联接,请调用 unbindService() 。
当客户端被销毁时,与服务的绑定也将解除。但与服务交互完毕后,或者你的activity进入pause状态时,你都应该确保解除绑定,以便服务能够在用完后及时关闭。
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // 与服务的联接建立之后将会调用 public void onServiceConnected(ComponentName className, IBinder service) { // 因为我们已经与明显是运行于同一进程中的服务建立了联接, // 我们就可以把它的IBinder转换为一个实体类并直接访问它。 LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // 与服务的联接意外中断时将会调用 public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mBound = false; } };
利用这个 ServiceConnection ,客户端就能够把它传入 bindService() 完成与服务的绑定。
Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
相关推荐
总的来说,《解析Google Android SDK——智能手机开发范例手册》覆盖了Android开发的多个重要方面,从基础环境到高级技术,为开发者提供了全面的学习资源。通过深入研究这些章节,开发者不仅可以构建功能丰富的...
在Android开发领域,从新手入门到成为专家是一个不断学习和实践的过程。《Android开发——从小工...《Android开发——从小工到专家》书签版,无疑为这一过程提供了便利,让开发者可以迅速找到关键信息,提高学习效率。
在安卓应用开发中,`Service` 是一个非常重要的组件,它用于在后台执行长时间运行的操作,即使用户与应用程序没有交互。本篇将深入探讨 `ServiceSample` 示例代码,帮助你理解如何在 Android 中有效地使用 `Service`...
描述中的 "安卓Android源码——GpsTracker源码.zip" 与标题相呼应,暗示了这是一个关于Android开发的项目,特别关注于GPS跟踪功能的实现。源码的提供是为了让开发者能够深入理解如何在Android应用中集成和操作GPS...
《Android系统级深入开发...以上是《Android系统级深入开发——移植与调试》一书可能涵盖的主要内容,通过学习这些知识点,开发者能够掌握Android系统的核心技术,为创建高效、稳定且安全的系统和应用打下坚实基础。
【Android Studio应用开发——基础入门与应用实战】是针对初学者和希望提升Android应用程序开发技能的人群设计的一门课程。这门课程由专家方欣和杨勃共同编写,旨在通过电子课件的形式,深入浅出地讲解Android ...
在Android开发领域,掌握基础知识是至关重要的。这份"Android教材"包含了关于Activity生命周期、Service使用以及Content Provider的讲解,这些都是Android应用开发的核心概念。 首先,我们来深入理解第六讲——...
本篇文章将深入探讨“Android学习之路——7.Service”,分析Service的基本概念、使用方式以及常见应用场景,同时结合源码解析Service的工作原理,并提供一个实战Demo——Service_Demo。 一、Service基本概念 ...
对于希望提升Android开发技能,尤其是与Google服务集成的开发者来说,深入研究这部分源码无疑会带来极大的收获。同时,这也是一种挑战,因为源码阅读需要扎实的编程基础和对Android系统架构的深入理解。但只要投入...
总的来说,通过深入学习《安卓Android源码——应用开发揭秘》中的源码,开发者不仅可以提升自己的编程技能,还能了解到Android系统的架构设计,从而在面对复杂问题时能够更有条理地分析和解决。这份源码资源是...
【Android 移动开发——打地鼠(Android Studio 版)...这个“打地鼠”项目是学习Android开发的绝佳实践,它涵盖了Android开发的诸多核心概念,通过实际操作,开发者可以更深入地理解和掌握Android应用开发的各个环节。
在安卓(Android)平台上,开发人员经常需要处理各种任务,其中一项常见的需求是备份和恢复用户的短信。这个压缩包文件“安卓Android源码——Gmail备份手机短信源码.zip”提供了一个示例,展示了如何利用Android SDK...
在安卓平台上,Widget小组件是应用与用户交互的一种方式,它们可以被添加到用户的主屏幕上,提供...这对于提高Android开发技能,尤其是对于那些希望为用户提供更直观、便捷服务的开发者来说,是一份宝贵的参考资料。
1. **Resources**:在Android开发中,资源文件通常存放于`res`目录下,包括了应用程序的各种非代码资源,如界面布局(XML文件)、图像资源(PNG、JPEG等)、字符串资源(strings.xml)、颜色资源(colors.xml)、...
在安卓(Android)平台上,开发一个能够实现应用自动更新的功能是一项常见的任务,它涉及到服务(Service)组件的使用...这涉及到了Android组件交互、网络编程、错误处理等多个方面,是Android开发中的一个重要技能。
本资源"安卓Android源码——通讯录的开发_完整代码.zip"提供了一个完整的通讯录应用开发案例,可以帮助开发者深入理解Android系统中关于联系人管理的底层机制以及UI设计的实践技巧。 1. **Android源码分析** - **...
在Android开发中,Shared Preferences是应用中保存轻量级数据的一种常见方式,它主要用于存储一些简单的键值对数据,如用户设置、应用状态等。在深入理解`sharedPref`的学习源码之前,我们先来回顾一下 Shared ...
总之,这份“安卓Android源码——安卓Android经典开发---豆瓣网移动客户端+讲解+源代码.rar”资料包为开发者提供了一个实践和学习Android开发的宝贵资源。通过深入研究豆瓣移动客户端的源码,开发者不仅可以掌握...
### Android系统的Binder机制之一——Service_Manager #### 一、引言 在深入探讨Android系统中的Binder机制之前,我们首先简要回顾一下Binder机制的基本概念及其重要性。Android系统基于Linux内核,但在进程间通信...