Binder其实就是,连接服务端和客户端的桥梁,Binder可以提供系统中任何程序都可以访问的全局服务。(这时,我们可能会想到AIDL,因为提到全局的服务,我们一般都会用到AIDL,这和Binder有什么关系呢?其实,AIDL的内部实现,归根结底也是利用Binder的框架,只不过AIDL的代码是系统自动帮我们生成的,所以我们一般借助AIDL以简化不同应用程序间访问的全局服务。)
我们可以把任意的应用程序看做是客户端,全局的服务看作是服务端。
客户端:客户端的请求通过客户端Binder对象,调用tansact方法,传递到服务端。
服务端:服务端同样通过服务端Binder对象,接收客户端传递过来的请求,然后处理请求(调用Binde对象的onTansact方法)。
为了简化,先先借助AIDL实现全局服务。
下面以一个加减运算的服务,简单介绍Binder实现全局服务,首先新建AIDL文件:
package com.example.administrator.myaidl;
// Declare any non-default types here with import statements
interface ICalcAIDL {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(int a , int b);
int min(int a,int b);
}
服务端代码:CalService类
package com.example.administrator.myaidl;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
/**
* Created by Administrator on 2015/12/25.
*/
public class CalService extends Service {
private static String Tag="Service";
@Override
public void onCreate() {
super.onCreate();
Log.e(Tag,"OnCreate()");
}
//绑定返回Binder对象mBinder,mBinder是ICalcAIDL.Stub的引用(ICalcAIDL是我上面新建的AIDL文件名,Stub是继承于Binder的)
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
Log.e(Tag,"OnDestroy()");
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(Tag,"onUnBinder()");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
Log.e(Tag,"OnRebind()");
super.onRebind(intent);
}
private final ICalcAIDL.Stub mBinder=new ICalcAIDL.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public int min(int a, int b) throws RemoteException {
return a-b;
}
};
}
在此Service中,使用生成的ICalcAIDL创建了一个mBinder的对象,并在Service的onBind方法中返回.此时系统会自动为我们生成ICalcAIDL.java文件,如下:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: F:\\duan\\Linux\\优快云Demo\\myaidl\\src\\main\\aidl\\com\\example\\administrator\\myaidl\\ICalcAIDL.aidl
*/
package com.example.administrator.myaidl;
// Declare any non-default types here with import statements
public interface ICalcAIDL extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.administrator.myaidl.ICalcAIDL
{
private static final java.lang.String DESCRIPTOR = "com.example.administrator.myaidl.ICalcAIDL";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.administrator.myaidl.ICalcAIDL interface,
* generating a proxy if needed.
*/
public static com.example.administrator.myaidl.ICalcAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.administrator.myaidl.ICalcAIDL))) {
return ((com.example.administrator.myaidl.ICalcAIDL)iin);
}
return new com.example.administrator.myaidl.ICalcAIDL.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_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_min:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.min(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.administrator.myaidl.ICalcAIDL
{
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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public int add(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_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int min(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_min, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_min = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
public int add(int a, int b) throws android.os.RemoteException;
public int min(int a, int b) throws android.os.RemoteException;
}
后面再解释自动生成的代码。
下面往清单文件里注册服务:
<service android:name=".CalService">
<intent-filter>
<action android:name="com.dfy.myaidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
这里我们给Service指定了一个name,因为我们一会会在别的应用程序中通过Intent来查找此Service;这个不需要Activity,所以我也就没写Activity,安装完成也看不到安装图标,悄悄在后台运行着。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="bindService"
android:text="BindService" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="unbindService"
android:text="UnbindService" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="addInvoked"
android:text="12+12" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="minInvoked"
android:text="50-12" />
</LinearLayout>
客户端代码:
package com.example.administrator.myaidl;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String Tag = "client";
private ICalcAIDL mCalcAidl;
private ServiceConnection mConn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(Tag,"onServiceConnection");
mCalcAidl = ICalcAIDL.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(Tag,"OnServiceDisconnected()");
mCalcAidl=null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bindService(View view ) {
Intent intent =new Intent();
intent.setAction("com.dfy.myaidl");
super.bindService(intent, mConn, Context.BIND_AUTO_CREATE);
}
public void unbindService(View view) {
super.unbindService(mConn);
}
public void addInvoked(View view) throws RemoteException {
if(mCalcAidl!=null){
int res= mCalcAidl.add(12,12);
Log.e("Tag","addInvoke()的结果:"+res);
Toast.makeText(this,res+"",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this,"服务器被异常杀死,重新连接!",Toast.LENGTH_SHORT).show();
}
}
public void minInvoked(View view) throws RemoteException {
if(mCalcAidl!=null){
int res=mCalcAidl.min(50,12);
Log.e(Tag, "minInvoke()的结果:"+res);
Toast.makeText(this,res+"",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "服务器异常,重新连接!",Toast.LENGTH_LONG).show();
}
}
}
ICalcAIDL.Stub.asInterface(iBinder)方法返回的是ICalcAIDL.Stub.Proxy对象。顾名思义就是ICalcAIDL的代理类,也是ICalcAIDL类型的。这里的iBinder对象就是客户端与连接服务器端建立连接时的IBinder,(也就是说是在服务器端初始化的mBinder)
所有代码到此结束!
下面具体结合自动生成的文件与服务端和客户端的联系。
自动生成的ICalcAIDL.java文件,看起来感觉很多,其实只需要关心几个模块即可,首先先看Stub定义:继承Binder,实现ICalcAIDL(我定义的aidl文件)
public static abstract class Stub extends android.os.Binder implements com.example.administrator.myaidl.ICalcAIDL
private final ICalcAIDL.Stub mBinder=new ICalcAIDL.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public int min(int a, int b) throws RemoteException {
return a-b;
}
};
再看
Stub类的onTansact方法:服务端的Binder实例会根据客户端发来的消息(依靠Binder对象),执行onTransact方法,然后由其参数决定执行服务端的代码。相信大家都看到里面的case判断语句了。
Stub类的asInterface()方法:这个方法关乎客户端代码,再次贴出客户端相关代码: private ServiceConnection mConn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(Tag,"onServiceConnection");
mCalcAidl = ICalcAIDL.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(Tag,"OnServiceDisconnected()");
mCalcAidl=null;
}
};
public static com.example.administrator.myaidl.ICalcAIDL asInterface(android.os.IBinder obj)
这个方法返回一个Proxy实例,这个Proxy实例传入了我们的Binder对象,并且封装了我们调用服务端的代码,客户端会通过Binder对象的transact()方法调用服务端代码。直接看Proxy的add方法。
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);//读取服务端端口,与服务器端enforceInterface(DESCRIPTOR)相对应
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();//客户端接收服务端返回的数据,
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
Proxy的min方法类似,略...总的过程可以这么理解:AIDL只不过是简化BInder框架的一个机制,(帮我们自动生成了代码)
下面是原生Binder框架实现与AIDL实现的具体细节:
我们需要了解里面的内部细节,1,在服务端:首先需要客户端与服务器建立连接时生成一个IBinder对象(这个IBinder对象是继承自Binder类,)
原生的Binder框架:在这个Binder类的内部需要复写onTransact(),方法内部是根据该方法的参数选择case语句分支,也就是选择不同的方法(需要提供的服务方法对应于AIDL用法里面建立的aidl文件)。
AIDL实现:先定义一个AID文件同样是需要一个IBinder对象,不过这里只需要实线Stub类的各种方法即可(Stub里面的各种方法就是定义的AIDL文件)。
2,在客户端:需要拿到在服务端初始化的IBInder对象,也即是在第一部中得到的IBinder对象,一般是从ServiceConnnectin类的onConnection方法中获取。
原生Binder框架:从ServiceConnnectin类的onConnection方法中获取,拿到IBinder对象,在需要调用服务的地方,向IBinder对象一步一步传入具体参数,并调用IBinder对象的onTransact()方法,向服务其传递参数,并等待服务器返回结果后,接收服务器返回的数据,(其实这里的onTransact方法就是第一部中生成IBInder对象时复写的onTransact方法)。
AIDL实现:在erviceConnnectin类的onConnection方法中通过IBinder对象,获取的是AIDL类型的类(提供服务的类)的代理对象,在需要调用服务的地方,直接调用该代理对象的相应方法就行,不需要向上面那样进行复杂的传递和接收工作。