Android--Service之绑定服务交互

简介:

使用IBinder接口

  如果看了之前关于Service博客的人,应该对IBinder接口有所了解,这里简单介绍一下IBinder。

  IBinder是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分。但它不仅用于远程调用,也可以用于进程内调用。这个接口定义了与远程对象交互的协议,一般不直接实现这个接口,而是从它的实现类Binder中继承。

  通过IBinder进行服务的交互一般有两种方式,一种方式是使用IBinder.transact()方法向远端的IBinder对象发送一个发出调用,会回调远端的Binder.onTransact()方法,这个方法传递的数据是Parcel。Parcel是一种缓冲区,除了数据外还有有一些描述它内容的元素,如果查看源码的话会发现,Parcel本质上是一个Serialize,只是它在内存中完成了序列化和反序列化,利用的是连续的内存空间,因此效率会更高,并且AIDL的数据也是通过Parcel来交互的。另外一种方法就是抛弃IBinder中原生的方法,使用自定义的接口方法进行数据交互,这也是Android官方推荐绑定服务的一种数据交互方式。当然,不管是使用transact()给远程服务交互,还是使用自定义的接口交互,都是同步执行的,直到远程服务执行完并返回结果才会继续向下执行。

  其他关于适应IBinder服务的内容,在博客Android--Service之基础中已经讲解过了,这里不再累述。下面使用一个例子来演示一下使用自定义接口与服务进行交互的例子。

  服务:IBinderSer.java

复制代码
 1 package cn.bgxt.servicebinddatedemo;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.Binder;
 6 import android.os.IBinder;
 7 import android.os.Parcel;
 8 import android.os.RemoteException;
 9 import android.util.Log;
10 
11 public class IBinderSer extends Service {
12     private final String TAG="main";
13     private final int MULTIPLE=1024;    
14     public  final IBinder mBinder=new LocalBinder();
15     
16     public class LocalBinder extends Binder{
17         // 在Binder中定义一个自定义的接口用于数据交互
18         // 这里直接把当前的服务传回给宿主
19         public IBinderSer getService(){
20             return IBinderSer.this;
21         }                
22     }
23     
24     @Override
25     public IBinder onBind(Intent intent) {
26         Log.i(TAG, "The service is binding!");
27         // 绑定服务,把当前服务的IBinder对象的引用传递给宿主
28         return mBinder;
29     }
30     
31     public int getMultipleNum(int num){
32         // 定义一个方法 用于数据交互
33         return MULTIPLE*num;
34     }
35 }
复制代码

  调用服务的Activity:IBinderActivity.java

复制代码
 1 package cn.bgxt.servicebinddatedemo;
 2 
 3 import android.app.Activity;
 4 import android.app.Service;
 5 import android.content.ComponentName;
 6 import android.content.Intent;
 7 import android.content.ServiceConnection;
 8 import android.os.Bundle;
 9 import android.os.IBinder;
10 import android.os.Messenger;
11 import android.os.Parcel;
12 import android.os.RemoteException;
13 import android.view.View;
14 import android.widget.Button;
15 import android.widget.Toast;
16 
17 public class IBinderActivity extends Activity {
18     private Button btnStart, btnInvoke, btnStop;
19     IBinderSer mService=null;
20     private ServiceConnection mConnection = new ServiceConnection() {
21 
22         @Override
23         public void onServiceDisconnected(ComponentName name) {
24             mService = null;
25         }
26 
27         @Override
28         public void onServiceConnected(ComponentName name, IBinder service) {
29             // 获取服务上的IBinder对象,调用IBinder对象中定义的自定义方法,获取Service对象
30             IBinderSer.LocalBinder binder=(IBinderSer.LocalBinder)service;
31             mService=binder.getService();
32         }
33     };
34     
35     @Override
36     protected void onCreate(Bundle savedInstanceState) {
37         super.onCreate(savedInstanceState);
38         setContentView(R.layout.layout_service);
39         btnStart = (Button) findViewById(R.id.btnStartSer);
40         btnInvoke = (Button) findViewById(R.id.btnInvokeMethod);
41         btnStop = (Button) findViewById(R.id.btnStopSer);
42         
43         btnStart.setOnClickListener(onclick);
44         btnInvoke.setOnClickListener(onclick);
45         btnStop.setOnClickListener(onclick);
46     }
47 
48     View.OnClickListener onclick = new View.OnClickListener() {
49 
50         @Override
51         public void onClick(View v) {
52             switch (v.getId()) {
53             case R.id.btnStartSer:
54                 Toast.makeText(getApplicationContext(), "绑定服务成功", Toast.LENGTH_SHORT).show();
55                 bindService(new Intent(IBinderActivity.this,IBinderSer.class),mConnection,Service.BIND_AUTO_CREATE);                
56                 break;
57             case R.id.btnInvokeMethod:
58                 if(mService==null){
59                     Toast.makeText(getApplicationContext(), "请先绑定服务", Toast.LENGTH_SHORT).show();
60                     return;
61                 }
62                 // 调用绑定服务上的方法,进行数据交互
63                 int iResult=mService.getMultipleNum(10);
64                 Toast.makeText(getApplicationContext(), "服务计算结果为:"+iResult, Toast.LENGTH_SHORT).show();
65                 break;
66             case R.id.btnStopSer:
67                 Toast.makeText(getApplicationContext(), "服务解除绑定", Toast.LENGTH_SHORT).show();
68                 unbindService(mConnection);
69                 mService=null;
70                 break;
71             default:
72                 break;
73             }
74         }
75     };
76 }
复制代码

  执行结果:

 

 

使用Messenger类

  除了使用IBinder之外,还可以使用Messenger,那么先来聊聊什么是Messenger。

  Messenger引用了一个Handler独享,可以使用Messenger.send(Message msg)方法跨进程向服务发送消息,只需要在服务中使用Handler创建一个Messenger,宿主持有这个Messenger就可以与服务进行通信。之前介绍的handler+Message的通信方式不同,那都是在同一个进程中的,从工作线程持有一个主线程的Handler对象,从而向主线程发送消息,这里不了解的可以看看之前的博客:Android--多线程之Handler。而上面介绍过了,Android可以使用IBinder实现跨进程通信,并且也将Handler与IBinder结合起来实现跨进程发送消息。

  当然这里提一下,Messenger管理的是一个消息队列,它会依据消息进入的先后次序予以执行,所以也不需要把服务设计为线程安全是。

   实现Messenger实现进程通信,主要有以下几点注意:

  1. 在服务中实现一个Handler类,并实例化它,在handleMessage()方法中接收客户端的请求。
  2. 在服务中使用这个Handler对象创建一个Messenger对象。
  3. 使用Messenger对象的getBinder()方法返回一个IBinder对象作为onBind()的返回值返回给客户端。
  4. 在客户端使用IBinder实例化一个Messenger对象,并使用它向服务端发送信息。

  下面通过一个简单的例子来演示一下利用Messenger在服务与客户端进行的通信。

  服务:MessengerSer.java

复制代码
 1 package cn.bgxt.servicebinddatedemo;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.Handler;
 6 import android.os.IBinder;
 7 import android.os.Message;
 8 import android.os.Messenger;
 9 import android.util.Log;
10 import android.widget.Toast;
11 
12 public class MessengerSer extends Service {
13     private final String TAG="main";
14     static final int MSG_SAY_HELLO = 1;
15 
16     public class IncomingHandler extends Handler {
17         @Override
18         public void handleMessage(Message msg) {
19             switch (msg.what) {
20             case MSG_SAY_HELLO:
21                 Toast.makeText(getApplicationContext(), "Service say hello!",
22                         Toast.LENGTH_SHORT).show();
23                 Log.i(TAG, "Service say hello!");
24                 break;
25             default:
26                 super.handleMessage(msg);
27             }
28         }
29     }
30 
31     IncomingHandler incomingHandler=new IncomingHandler();
32      final Messenger mMessenger=new Messenger(new IncomingHandler());
33      
34     @Override
35     public IBinder onBind(Intent arg0) {
36         return mMessenger.getBinder();
37     }
38 
39 }
复制代码

  服务绑定的Activity:MessengerActivity.java

复制代码
 1 package cn.bgxt.servicebinddatedemo;
 2 
 3 
 4 import android.app.Activity;
 5 import android.app.Service;
 6 import android.content.ComponentName;
 7 import android.content.Intent;
 8 import android.content.ServiceConnection;
 9 import android.os.Bundle;
10 import android.os.IBinder;
11 import android.os.Message;
12 import android.os.Messenger;
13 import android.os.RemoteException;
14 import android.view.View;
15 import android.widget.Button;
16 import android.widget.Toast;
17 
18 public class MessengerActivity extends Activity {
19     private Button btnStart, btnInvoke, btnStop;
20     private Messenger mService = null;
21 
22     private ServiceConnection mConnection = new ServiceConnection() {
23 
24         @Override
25         public void onServiceDisconnected(ComponentName name) {
26             mService = null;
27         }
28 
29         @Override
30         public void onServiceConnected(ComponentName name, IBinder service) {
31             // 使用服务端的IBinder对象实例化一个Messenger对象
32             mService = new Messenger(service);
33         }
34     };
35     @Override
36     protected void onCreate(Bundle savedInstanceState) {
37         // TODO Auto-generated method stub
38         super.onCreate(savedInstanceState);
39         setContentView(R.layout.layout_service);
40         btnStart = (Button) findViewById(R.id.btnStartSer);
41         btnInvoke = (Button) findViewById(R.id.btnInvokeMethod);
42         btnStop = (Button) findViewById(R.id.btnStopSer);
43         
44         btnStart.setOnClickListener(onclick);
45         btnInvoke.setOnClickListener(onclick);
46         btnStop.setOnClickListener(onclick);
47     }
48 
49     View.OnClickListener onclick = new View.OnClickListener() {
50 
51         @Override
52         public void onClick(View v) {
53             switch (v.getId()) {
54             case R.id.btnStartSer:
55                 Toast.makeText(getApplicationContext(), "绑定服务成功", Toast.LENGTH_SHORT).show();
56                 bindService(new Intent(getApplicationContext(),MessengerSer.class), mConnection, Service.BIND_AUTO_CREATE);
57                 break;
58             case R.id.btnInvokeMethod:
59                 if(mService==null){
60                     Toast.makeText(getApplicationContext(), "请先绑定服务",Toast.LENGTH_SHORT).show();
61                     return ;
62                 }
63                 // 实例化一个Message对象
64                 Message msg=Message.obtain(null, MessengerSer.MSG_SAY_HELLO, 0, 0);
65                 try{
66                     // 把Message独享传递给服务端处理
67                     mService.send(msg);
68                 }
69                 catch(RemoteException e){
70                     e.printStackTrace();
71                 }
72                 break;
73             case R.id.btnStopSer:
74                 Toast.makeText(getApplicationContext(), "服务解除绑定", Toast.LENGTH_SHORT).show();
75                 unbindService(mConnection);
76                 mService=null;
77                 break;
78             default:
79                 break;
80             }
81 
82         }
83     };
84 }
复制代码

  执行结果:

 

 

使用AIDL

  AIDL(Android Interface Definition Language),它可以实现跨进程间的通信。之前讲到的Messenger实现跨进程通信,其实也是基于AIDL作为底层结构。但是正如上面提到的,Messenger创建的一个消息队列是在一个单独的线程中,所以服务一次仅处理一个请求,然而,如果想要服务同时处理多个请求,就需要使用到AIDL,但是这种情况下就要考虑多线程和线程安全的问题了。这个不在本篇博客的范畴内,以后有机会在细细讲解。


本文转自承香墨影博客园博客,原文链接:http://www.cnblogs.com/plokmju/p/android_ServiceCommunication.html,如需转载请自行联系原作者


相关文章
|
3月前
|
安全 API Android开发
Android网络和数据交互: 解释Retrofit库的作用。
Android网络和数据交互: 解释Retrofit库的作用。
38 0
|
5月前
|
开发工具 数据库 Android开发
0001Java安卓程序设计-基于Android多餐厅点餐桌号后厨前台服务设计与开发2
0001Java安卓程序设计-基于Android多餐厅点餐桌号后厨前台服务设计与开发
28 0
|
4月前
|
XML Java Android开发
Android Studio App开发之服务Service的讲解及实战(包括启动和停止,绑定与解绑,推送服务到前台实现音乐播放器,附源码)
Android Studio App开发之服务Service的讲解及实战(包括启动和停止,绑定与解绑,推送服务到前台实现音乐播放器,附源码)
98 0
|
3天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android's AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
5 0
|
3天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
5 0
|
1月前
|
移动开发 JavaScript Android开发
Android与Html5交互
Android与Html5交互
|
6月前
|
SQL 人工智能 移动开发
Android应用启动流程:从启动到可交互的过程解析
Android应用启动流程:从启动到可交互的过程解析
|
2月前
|
XML Android开发 数据格式
安卓和webview交互
安卓和webview交互
25 0
|
3月前
|
开发工具 Android开发
Android平台RTMP推送|轻量级RTSP服务|GB28181设备接入模块之实时快照保存JPG还是PNG?
Android平台RTMP推送|轻量级RTSP服务|GB28181设备接入模块之实时快照保存JPG还是PNG?
|
3月前
|
数据采集 编解码 图形学
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
100 0