Binder机制概述
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Binder机制概述相关的知识,希望对你有一定的参考价值。
参考技术A android进程间通讯是通过Binder机制来实现的,Android是基于linux系统因此有必要了解Linux系统进程相关知识.Linux系统中(其他系统也是这样)不同进程之间不允许直接操作或访问另一进程.也就是进程隔离.
为了保证用户进程不能直接访问内核,操作系统从逻辑上将虚拟空间划分为用户空间和内核空间.内核程序运行在内核空间(kernel space),应用程序运行在用户空间(user space).为了安全,他们之间是隔离的,即使用户程序奔溃了,也不会影响内核.内核空间数据是可以共享的,用户空间不可以.
用户空间访问内核空间只能通过系统调用,系统调用是用户空间访问内核空间的唯一方式,保证所有资源访问在内核控制下,避免了用户对系统资源的越权访问,提高了系统安全性和稳定性.
copy_from_user:将用户空间数据拷贝到内核空间
copy_to_user:将内核空间数据拷贝到用户空间
由于用户进程不能直接访问硬件地址,所以系统提供了一种机制:内存映射(Memory Map).在Linux中通过调用函数mmap实现内存映射,将用户空间一块内存地址映射到内核空间.映射关系建立后,对用户空间内存的修改可以反应到内核空间.内存映射可减少拷贝次数.
如果没有内存映射,用户进程需要访问硬盘文件时,需要在内核空间创建一片页缓存,将硬盘文件数据拷贝到页缓存然后用户进程在拷贝页缓存数据,需要两次拷贝.通过内存映射后硬盘文件可以和内核的虚拟内存直接映射,减少一次拷贝.
如图
inter-process-communication进程间通信,指进程间交换数据的过程.
Linux提供了很多进程间通讯的机制,主要有管道(pipe)、消息队列(Message)、信号(sinal)、信号量(semophore)、套接字(socket)等
内核程序在内核空间分配并开辟一块内核缓冲区,发送进程将数据通过copy_from_user拷贝到内核空间的数据缓冲区,内核空间通过copy_to_user将数据拷贝到接收进程,这样就实现了一次进程间通信.如图
Linux的IPC机制有两个问题:
1.数据通过用户空间->内核空间->用户空间,经过两次拷贝,效率不高
2.接收进程无法预先知道数据大小,只能尽可能大创建数据缓冲区,或通过api消息头获取消息体的大小,浪费了空间或时间.
Android进程间通信通过Binder实现,下面介绍Binder机制通信原理,为什么是Binder
内核程序创建一个数据接收缓存区,同时创建一个内核缓冲区.并建立内核缓冲区和数据接收缓冲区内存映射,以及数据内核缓冲区和接收进程用户空间的映射关系.发送进程通过copy_from_user将数据拷贝到内核数据接收缓冲区,因为内核数据接收缓冲区和内核缓冲区以及接收进程用户空间存在映射关系,相当于将数据发送到了接收进程.完成了一次进程间通信.如图
Binder机制是c/s架构的,由Client、server、ServiceManager和Binder组成.client、server和serviceManager都是独立的进程,由于Linux进程隔离的原因,所以需要借助Binder进行通信.
Binder通信主要有三个步骤:注册服务、获取服务、使用服务.如下图
从上一条Binder实现原理示例图中可以看到,Binder可分为Java Binder、Native Binder和Kernal Binder.应用开发需要了解Java Binder和Navive Binder.这里只介绍Binder基本原理.具体可查看文章结尾的链接.
感谢
https://blog.csdn.net/itachi85/article/details/102713845
https://www.jianshu.com/p/429a1ff3560c
https://blog.csdn.net/carson_ho/article/details/73560642?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159651217319195188353096%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=159651217319195188353096&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2 all first_rank_ecpm_v3~rank_business_v1-1-73560642.ecpm_v3_rank_business_v1&utm_term=Binder&spm=1018.2118.3001.4187
Android Binder机制完全解析
概述
之前我写过一篇文章Android Service全面解析,简单实现了如何通过AIDL实现Service的跨进程通信(IPC),其实是通过Binder机制来实现的,本文我们就重点来看看Binder机制的原理。
Binder可以提供系统中任何程序都可以访问的全局服务。这个功能当然是任何系统都应该提供的,下面我们简单看一下Android的Binder的框架:
Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;简单想一下,需要提供一个全局服务,那么全局服务那端即是服务器接口,任何程序即客户端接口,它们之间通过一个Binder驱动访问。
- 服务器接口:实际上是Binder类的对象,该对象一旦创建,内部则会启动一个隐藏线程,接收Binder驱动发送的消息,收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。
- Binder驱动:该对象也为Binder类的实例,客户端通过该对象访问远程服务。
- 客户端接口:获得Binder驱动,调用其transact()发送消息至服务器。
实例实现
如果你觉得上面的描述太抽象了,没关系,下面我们通过一个具体的例子来看看Binder机制的原理。例子我仍然使用上一篇文章的例子,不过之前我是使用Eclipse创建工程,今天我们使用Studio来创建项目,效果都是一样的。
(1)Studio创建两个Module,app代表客户端程序,binder_server代表服务器端程序。
(2)创建aidl文件
在app目录上右键,NEW->AIDL->AIDL File,创建一个aidl文件(IMyAidlInterface.aidl),同时必须要指明包名,包名必须和java目录下的包名一致。此aidl文件会默认生成到aidl目录下,aidl目录和java目录同级别。
IMyAidlInterface.aidl文件内容:
interface IMyAidlInterface
int plus(int a, int b);
String toUpperCase(String str);
build一下,会自动生成IMyAidlInterface.java文件,不同于Eclipse的gen目录,studio下的java文件目录为:
*(项目名)\\app\\build\\generated\\source\\aidl\\debug\\com\\hx\\binder\\IMyAidlInterface.java
关于IMyAidlInterface.java文件内容,我们后面会具体分析,这里先省略。
(3)将aidl文件连同目录一起拷贝到服务器端
(4)服务器端新建服务MyRemoteService
public class MyRemoteService extends Service
@Override
public void onCreate()
super.onCreate();
MainActivity.showlog("onCreate()");
@Override
public int onStartCommand(Intent intent, int flags, int startId)
MainActivity.showlog("onStartCommand()");
return super.onStartCommand(intent, flags, startId);
@Override
public void onDestroy()
super.onDestroy();
MainActivity.showlog("onDestroy()");
@Override
public IBinder onBind(Intent intent)
MainActivity.showlog("onBind()");
return mBinder;
@Override
public boolean onUnbind(Intent intent)
MainActivity.showlog("onUnbind()");
return super.onUnbind(intent);
IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub()
@Override
public String toUpperCase(String str) throws RemoteException
if (str != null)
return str.toUpperCase();
return null;
@Override
public int plus(int a, int b) throws RemoteException
return a + b;
;
在Manifest中进行注册:
<service android:name=".MyRemoteService"
android:exported="true">
<intent-filter>
<action android:name="com.hx.action.remoteService" />
</intent-filter>
</service>
(4)编写客户端代码
public class MainActivity extends Activity implements View.OnClickListener
private Button bindService;
private Button unbindService;
private Button plus;
private Button toUpperCase;
private IMyAidlInterface myAIDLInterface;
private ServiceConnection connection = new ServiceConnection()
@Override
public void onServiceDisconnected(ComponentName name)
myAIDLInterface = null;
Toast.makeText(MainActivity.this, "onServiceDisconnected", Toast.LENGTH_SHORT).show();
@Override
public void onServiceConnected(ComponentName name, IBinder service)
myAIDLInterface = IMyAidlInterface.Stub.asInterface(service);
Toast.makeText(MainActivity.this, "onServiceConnected", Toast.LENGTH_SHORT).show();
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService = (Button) findViewById(R.id.bind_service);
unbindService = (Button) findViewById(R.id.unbind_service);
plus = (Button) findViewById(R.id.plus);
toUpperCase = (Button) findViewById(R.id.toUpperCase);
//button点击事件
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
plus.setOnClickListener(this);
toUpperCase.setOnClickListener(this);
@Override
public void onClick(View v)
switch (v.getId())
case R.id.bind_service:
Intent intent = new Intent("com.hx.action.remoteService");
//5.0以上安卓设备,service intent必须为显式指出
Intent eintent = new Intent(getExplicitIntent(this,intent));
bindService(eintent, connection, Context.BIND_AUTO_CREATE);
// bindService(intent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
if(myAIDLInterface != null)
unbindService(connection);
break;
case R.id.plus:
if (myAIDLInterface != null)
try
int result = myAIDLInterface.plus(13, 19);
Toast.makeText(this, result + "", Toast.LENGTH_SHORT).show();
catch (RemoteException e)
e.printStackTrace();
else
Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
break;
case R.id.toUpperCase:
if (myAIDLInterface != null)
try
String upperStr = myAIDLInterface.toUpperCase("hello aidl service");
Toast.makeText(this, upperStr + "", Toast.LENGTH_SHORT).show();
catch (RemoteException e)
e.printStackTrace();
else
Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
break;
default:
break;
public static Intent getExplicitIntent(Context context, Intent implicitIntent)
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1)
return null;
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<Button
android:id="@+id/bind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="bind service" />
<Button
android:id="@+id/unbind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="unbind service" />
<Button
android:id="@+id/plus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="13 + 19" />
<Button
android:id="@+id/toUpperCase"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="hello aidl service" />
</LinearLayout>
运行程序,看效果:
我们首先点击BIND SERVICE按钮,绑定服务,会弹出“onServiceConnected”的Toast,说明服务绑定成功,获取到了服务器端的Binder驱动。
服务端Log:
然后分别点击13+19和hello aidl service按钮,可以通过Binder驱动调用服务端的代码并返回正确的计算结果。
最后点击UNBIND SERVICE按钮,我们的期望是弹出“onServiceDisconnected”的Toast,解除绑定,实际上呢?很遗憾没有弹出。
服务端Log:
由于我们当前只有一个客户端绑定了此Service,所以Service调用了onUnbind和onDestory。当我们继续点击13+19按钮,发现依然可以正确执行得到结果,也就是说即使onUnbind被调用,连接也是不会断开的,那么什么时候会断开连接呢?
即当服务端被异常终止的时候,比如我们现在在手机的正在执行的程序中找到该服务,并强行停止它:
可以看到这时弹出了“onServiceDisconnected”的Toast,说明连接被断开。之后再次点击13+19按钮,则会弹出Toast提示“服务器被异常杀死,请重新绑定服务端”。
原理分析
还记得我们上面根据aidl文件生成的Java文件吗?我们来看看它的结构吧:
public interface IMyAidlInterface extends android.os.IInterface
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.hx.binder.IMyAidlInterface
private static final java.lang.String DESCRIPTOR = "com.hx.binder.IMyAidlInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub()
this.attachInterface(this, DESCRIPTOR);
/**
* Cast an IBinder object into an com.hx.binder.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.hx.binder.IMyAidlInterface asInterface(android.os.IBinder obj)
if ((obj == null))
return null;
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.hx.binder.IMyAidlInterface)))
return ((com.hx.binder.IMyAidlInterface) iin);
return new com.hx.binder.IMyAidlInterface.Stub.Proxy(obj);
@Override
public android.os.IBinder asBinder()
return this;
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
switch (code)
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_plus:
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.plus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
case TRANSACTION_toUpperCase:
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.toUpperCase(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
return super.onTransact(code, data, reply, flags);
private static class Proxy implements com.hx.binder.IMyAidlInterface
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
mRemote = remote;
@Override
public android.os.IBinder asBinder()
return mRemote;
public java.lang.String getInterfaceDescriptor()
return DESCRIPTOR;
@Override
public int plus(int a, int b) throws android.os.RemoteException
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
finally
_reply.recycle();
_data.recycle();
return _result;
@Override
public java.lang.String toUpperCase(java.lang.String str) throws android.os.RemoteException
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(str);
mRemote.transact(Stub.TRANSACTION_toUpperCase, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
finally
_reply.recycle();
_data.recycle();
return _result;
static final int TRANSACTION_plus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_toUpperCase = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public int plus(int a, int b) throws android.os.RemoteException;
public java.lang.String toUpperCase(java.lang.String str) throws android.os.RemoteException;
代码比较长,但思路还是比较清晰的,IMyAidlInterface.java文件包含两个静态内部类—Stub和Proxy(其中Proxy是Stub的内部类)。
public static abstract class Stub extends android.os.Binder implements com.hx.binder.IMyAidlInterface
其中Stub是个抽象类,它继承了Binder,并实现了IMyAidlInterface接口。Stub提供了几个方法:asInterface、asBinder、onTransact,但并没有实现IMyAidlInterface接口的方法,所以需要交给Stub的实现类去实现。
private static class Proxy implements com.hx.binder.IMyAidlInterface
Proxy是Stub的内部类,也实现了IMyAidlInterface接口。并提供了几个方法:asBinder、getInterfaceDescriptor,并实现了IMyAidlInterface接口的方法plus和toUpperCase。
接下来看看服务端和客户端是如何和这个文件建立关联的吧。
服务端:
IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub()
@Override
public String toUpperCase(String str) throws RemoteException
if (str != null)
return str.toUpperCase();
return null;
@Override
public int plus(int a, int b) throws RemoteException
return a + b;
;
可以看到我们服务端提供的服务是由IMyAidlInterface.Stub来执行的,上面分析过,Stub这个类是Binder的子类,是不是符合我们文章开头所说的服务端其实是一个Binder类的实例。而且mBinder实现了IMyAidlInterface接口的方法。
接下来看Stub的onTransact()方法:
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
switch (code)
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_plus:
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.plus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
case TRANSACTION_toUpperCase:
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.toUpperCase(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
return super.onTransact(code, data, reply, flags);
文章开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。
可以看到onTransact有四个参数:code , data ,replay , flags
- code:是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法
- data:客户端传递过来的参数
- reply:服务器返回回去的值
- flags:标明是否有返回值,0为有(双向),1为没有(单向)
我们仔细看case TRANSACTION_plus中的代码:
data.enforceInterface(DESCRIPTOR);
与客户端的writeInterfaceToken对应,标识远程服务的名称
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
接下来分别读取了客户端传入的两个参数
int _result = this.plus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
然后执行this.plus,即我们服务端实现的plus方法;返回result由reply写回。
toUpperCase同理,可以看到服务端通过AIDL生成的Stub类,封装了服务端本来需要写的代码。
客户端
客户端主要通过ServiceConnected与服务端连接
private ServiceConnection connection = new ServiceConnection()
@Override
public void onServiceDisconnected(ComponentName name)
isConnected = false;
Toast.makeText(MainActivity.this, "onServiceDisconnected", Toast.LENGTH_SHORT).show();
@Override
public void onServiceConnected(ComponentName name, IBinder service)
isConnected = true;
myAIDLInterface = IMyAidlInterface.Stub.asInterface(service);
Toast.makeText(MainActivity.this, "onServiceConnected", Toast.LENGTH_SHORT).show();
;
其实这个onServiceConnected中的IBinder实例,其实就是我们文章开头所说的Binder驱动,也是一个Binder实例。
在IMyAidlInterface.Stub.asInterface中最终调用了:
return new com.hx.binder.IMyAidlInterface.Stub.Proxy(obj);
这个Proxy实例传入了我们的Binder驱动,并且封装了我们调用服务端的代码,文章开头说,客户端会通过Binder驱动的transact()方法调用服务端代码。
直接看Proxy中的plus方法
public int plus(int a, int b) throws android.os.RemoteException
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
finally
_reply.recycle();
_data.recycle();
return _result;
首先声明两个Parcel对象,一个用于传递数据,一个用户接收返回的数据
_data.writeInterfaceToken(DESCRIPTOR);
与服务器端的enforceInterfac对应
_data.writeInt(a);
_data.writeInt(b);
写入需要传递的参数
mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
终于看到了我们的transact方法,第一个对应服务端的code,_data,_reply分别对应服务端的data,reply,0表示是双向的
_reply.readException();
_result = _reply.readInt();
最后读出我们服务端返回的数据,然后return。可以看到和服务端的onTransact基本是一行一行对应的。
注意:
- 当客户端调用transact方法发起RPC(远程过程调用)请求后,当前线程会挂起,等待服务器端的返回结果。所以如果一个远程方法很耗时,那么不能再UI线程中调用此远程方法。
- 服务端的Binder方法(onTransact)运行在Binder线程池中,所以Binder方法不管是否耗时,都应该采取同步机制,因为它已经运行在一个线程中了。
到此,我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。
AIDL其实通过我们写的aidl文件,帮助我们生成了一个接口,一个Stub类用于服务端,一个Proxy类用于客户端调用。
不依赖AIDL实现IPC通信
那么我们是否可以不通过写aidl文件来实现远程的通信呢?下面向大家展示如何完全不依赖AIDL来实现客户端与服务端的通信。
服务端代码:
public class MyRemoteService extends Service
private static final String DESCRIPTOR = "MyRemoteService";
private static final int TRANSACTION_plus = 0x110;
private static final int TRANSACTION_toUpperCase = 0x111;
@Override
public void onCreate()
super.onCreate();
MainActivity.showlog("onCreate()");
@Override
public int onStartCommand(Intent intent, int flags, int startId)
MainActivity.showlog("onStartCommand()");
return super.onStartCommand(intent, flags, startId);
@Override
public void onDestroy()
super.onDestroy();
MainActivity.showlog("onDestroy()");
@Override
public IBinder onBind(Intent intent)
MainActivity.showlog("onBind()");
return mBinder;
@Override
public boolean onUnbind(Intent intent)
MainActivity.showlog("onUnbind()");
return super.onUnbind(intent);
private MyBinder mBinder = new MyBinder();
private class MyBinder extends Binder
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
switch (code)
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_plus:
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = _arg0 + _arg1;
reply.writeNoException();
reply.writeInt(_result);
return true;
case TRANSACTION_toUpperCase:
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = _arg0.toUpperCase();
reply.writeNoException();
reply.writeString(_result);
return true;
return super.onTransact(code, data, reply, flags);
;
<service android:name=".MyRemoteService"
android:exported="true">
<intent-filter>
<action android:name="com.hx.action.remoteService" />
</intent-filter>
</service>
客户端代码:
public class MainActivity extends Activity implements View.OnClickListener
private Button bindService;
private Button unbindService;
private Button plus;
private Button toUpperCase;
private IBinder myBinder;
private static final String DESCRIPTOR = "MyRemoteService";
private static final int TRANSACTION_plus = 0x110;
private static final int TRANSACTION_toUpperCase = 0x111;
private ServiceConnection connection = new ServiceConnection()
@Override
public void onServiceDisconnected(ComponentName name)
myBinder = null;
Toast.makeText(MainActivity.this, "onServiceDisconnected", Toast.LENGTH_SHORT).show();
@Override
public void onServiceConnected(ComponentName name, IBinder service)
myBinder = service;
Toast.makeText(MainActivity.this, "onServiceConnected", Toast.LENGTH_SHORT).show();
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService = (Button) findViewById(R.id.bind_service);
unbindService = (Button) findViewById(R.id.unbind_service);
plus = (Button) findViewById(R.id.plus);
toUpperCase = (Button) findViewById(R.id.toUpperCase);
//button点击事件
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
plus.setOnClickListener(this);
toUpperCase.setOnClickListener(this);
@Override
public void onClick(View v)
switch (v.getId())
case R.id.bind_service:
Intent intent = new Intent("com.hx.action.remoteService");
//5.0以上安卓设备,service intent必须为显式指出
Intent eintent = new Intent(getExplicitIntent(this,intent));
bindService(eintent, connection, Context.BIND_AUTO_CREATE);
// bindService(intent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
if(myBinder != null)
unbindService(connection);
break;
case R.id.plus:
if (myBinder != null)
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(78);
_data.writeInt(95);
myBinder.transact(TRANSACTION_plus, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
catch (RemoteException e)
e.printStackTrace();
finally
_reply.recycle();
_data.recycle();
else
Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
break;
case R.id.toUpperCase:
if (myBinder != null)
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString("my new programe");
myBinder.transact(TRANSACTION_toUpperCase, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
catch (RemoteException e)
e.printStackTrace();
finally
_reply.recycle();
_data.recycle();
else
Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
break;
default:
break;
public static Intent getExplicitIntent(Context context, Intent implicitIntent)
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1)
return null;
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<Button
android:id="@+id/bind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="bind service" />
<Button
android:id="@+id/unbind_service"
android:layout_width="match_parent"
android:layout_height=以上是关于Binder机制概述的主要内容,如果未能解决你的问题,请参考以下文章