1.BInder驱动机制说明
首先Binder是用于进程间通讯,这个我们都知道,但是它是基于Binder驱动来完成进程间通讯的。Binder驱动是一个驱动程序,而这个驱动程序存在于Linux内核层,Linux内核层又可以说是操作系统层,是进程的管理者。
一个进程A要调用进程B的一个方法,这个进程A就需要获取进程B的Binder代理对象,这个BInder代理对象就是进程B的BInder本地对象。当然这个Binder本地对象需要我们在进程B去实现在Service里面,实现的同时还要实现进程A想要调用方法。而在进程A里也要实现Binder代理对象。 进程A调用Binder代理对象时会通知Binder驱动,Binder驱动又会去调用进程B实现的Binder本地对象到实现的方法。
这里要注意为何BInder驱动能够知道进程A和进程B的所在,首先进程也可以看做内存里的一个地址,然后无论是BInder代理对象和Binder本地对象都会实现IBinder接口,都会在ServiceManager里注册地址通过所在的Service的名字(比如:Action)注册的,这样一来双方通过像是访问Service就可以访问对方的IBinder实现类。首先要注意无论是注册还是传递数据、回调数据都是通过Binder驱动实现,具体Binder驱动如何实现我们不需要知道,我们所能做的就是实现BInder本地对象和Binder代理对象。
2.BInder的使用方法
Server端负责实现Binder本地对象,Client负责实现Binder代理对象,实现Client端要调用Server完成两个不同计算函数。这里既然要调用两个函数,我们就要教两者学会如何分辨,就像使用handler一样,通过数字来分辨,毕竟占用字节少。
mPlusBinder.transact(0x110, _data, _reply, 0);
因为调用函数会有返回值,所以我们在使用Binder代理对象调用函数时需要首先传输数据过去,然后在接收数据。
_data.writeInterfaceToken("CalcPlusService");
_data.writeInt(36);
_data.writeInt(12);
mPlusBinder.transact(0x111, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
同时Server端需要首先接收函数,进过计算再返回值
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = _arg0 * _arg1;
reply.writeNoException();
reply.writeInt(_result);
完整实例代码如下
BinderServer的代码
public class CalcPlusService extends Service
{
private static final String DESCRIPTOR = "CalcPlusService";
private static final String TAG = "CalcPlusService";
public void onCreate()
{
Log.e(TAG, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
public IBinder onBind(Intent t)
{
Log.e(TAG, "onBind");
return mBinder;
}
public void onDestroy()
{
Log.e(TAG, "onDestroy");
super.onDestroy();
}
public boolean onUnbind(Intent intent)
{
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
public void onRebind(Intent intent)
{
Log.e(TAG, "onRebind");
super.onRebind(intent);
}
private MyBinder mBinder = new MyBinder();
private class MyBinder extends Binder
{
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException
{
switch (code)
{
case 0x110:
{
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 0x111:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = _arg0 / _arg1;
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
};
}
<service android:name="com.example.zhy_binder.CalcPlusService" >
<intent-filter>
<action android:name="com.zhy.aidl.calcplus" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
BinderClient
public class MainActivity extends Activity
{
private IBinder mPlusBinder;
private ServiceConnection mServiceConnPlus = new ServiceConnection()
{
@Override
public void onServiceDisconnected(ComponentName name)
{
Log.e("client", "mServiceConnPlus onServiceDisconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
Log.e("client", " mServiceConnPlus onServiceConnected");
mPlusBinder = service;
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bindService(View view)
{
Intent intentPlus = new Intent();
intentPlus.setAction("com.zhy.aidl.calcplus");
boolean plus = bindService(intentPlus, mServiceConnPlus,
Context.BIND_AUTO_CREATE);
Log.e("plus", plus + "");
}
public void unbindService(View view)
{
unbindService(mServiceConnPlus);
}
public void mulInvoked(View view)
{
if (mPlusBinder == null)
{
Toast.makeText(this, "未连接服务端或服务端被异常杀死", Toast.LENGTH_SHORT).show();
} else
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
{
_data.writeInterfaceToken("CalcPlusService");
_data.writeInt(50);
_data.writeInt(12);
mPlusBinder.transact(0x110, _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();
}
}
}
public void divInvoked(View view)
{
if (mPlusBinder == null)
{
Toast.makeText(this, "未连接服务端或服务端被异常杀死", Toast.LENGTH_SHORT).show();
} else
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
{
_data.writeInterfaceToken("CalcPlusService");
_data.writeInt(36);
_data.writeInt(12);
mPlusBinder.transact(0x111, _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();
}
}
}
}
<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="mulInvoked"
android:text="50*12" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="divInvoked"
android:text="36/12" />
</LinearLayout>