您的位置:首页 > 移动开发 > Android开发

Android中的进程机制(Binder)

2015-09-04 21:22 423 查看
很长时间没写博客 比较忙 今天突然闲下来 还是写写最近学习的结果 给自己加深一遍印象 开始我想从头开始写的 可是 有些东西感觉。。。是吧 你懂吧 所有我就把我最近学的东西 写写 请大家多多提出您的宝贵意见 好了不扯了 进入正题。。前几天去面试 CTO突然问我 你说一下安卓中线程跟进程通讯的机制 我一听线程 张口就来了 然后 到进程 我就操蛋了。。。。这进程怎么通讯我还真不知道,, 结果是吧你懂的。。然后我回家自己查资料 突然在安卓巴士上面看到Binder通讯机制 恍然大悟 (可能我理解的不对 大家指出错误 互相学习 。。。)安卓中service组件可以运行在同一进程中 也可以运行在不同的进程中,当运行在同一进程中的时候通讯就很简单 然而运行在不同的进程中的时候就需要我们要讲的Binder机制了 如图 系统组件主要包括四种 Client Service ServiceManager Binder DriverClient Service ServiceManager运行在User Space(用户态) Binder运行在Linux 内核态 我们的ServiceManager负责管理Service并向Client端提供一个代理接口 然后客户端调用代理接口中的方法就可以使用service提供的服务了 大体分为3步1.Client调用代理接口中的方法将参数打包 然后发给内核空间的Binder Driver2.Service读取到Binder Driver中的请求数据,将Client端传过来的参数进行处理3.处理完以后将结果交给Binder Driver 然后交给Client另外说一句 这个处理过程是同步的 当Service返回结果以前 Client端是阻塞的下面我就列出网上一个Demo大概说一下整个流程 大家可以自己写写看 (本人懒 没写 呵呵)创建一个aidl文件内容如下 里面定义两个方法一个 加 减法
interface MyAIDL {
int add(int a,int b);
int minus(int a,int b);
}
然后用的工具可能不一样 我用的AS然后rebuild一下 会生成java文件(一个接口) 里面包含了一个名为Stub的静态抽象类(待会详细分析)然后我们需要实现服务端方面的功能,创建一个service,我们顺手把生命周期中各方法都打印出来,并完成加法和减法函数的实现:
public class MyService extends Service {
private static final String TAG="SERVER";
public MyService() {
}
@Override
public void onCreate() {
super.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);
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,"onBind");
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG,"onDestroy");
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG,"onUnbind");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
Log.e(TAG,"onRebind");
super.onRebind(intent);
}
private final MyAIDL.Stub mBinder=new MyAIDL.Stub(){
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public int minus(int a, int b) throws RemoteException {
return a-b;
}
};
}
在service中,我们使用刚刚生成的MyAIDL.Stub静态抽象类创建了一个Binder对象,实现了其中有关计算的业务方法,并在onBind方法中返回它。另外我们还需要在manifest文件中对该服务进行注册:
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.cqumonk.adil.calculate"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
这时候,我们的服务端工作就完成了。我们开始编写客户端的代码来调用这个服务。首先,我们定义一个activity,包含四个按钮:然后我们可以在activity中启动之前定义好的service并调用它所提供的服务:(copy网上的自己懒 没写)
public class MainActivity extends Activity implements View.OnClickListener {
Button mBind;
Button mUnbind;
Button mAdd;
Button mMinus;
TextView txt_res;
private static final String TAG="CLIENT";
private MyAIDL mAIDL;
private boolean binded=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBind= (Button) findViewById(R.id.btn_bind);
mUnbind= (Button) findViewById(R.id.btn_unbind);
mAdd= (Button) findViewById(R.id.btn_add);
mMinus= (Button) findViewById(R.id.btn_minus);
txt_res= (TextView) findViewById(R.id.txt_res);
mBind.setOnClickListener(this);
mUnbind.setOnClickListener(this);
mAdd.setOnClickListener(this);
mMinus.setOnClickListener(this);
}
@Override
protected void onStop() {
super.onStop();
unbind();
}
private void unbind(){
if (binded){
unbindService(mConnection);
binded=false;
}
}
@Override
public void onClick(View v) {
int id=v.getId();
switch (id){
case R.id.btn_bind:
Intent intent=new Intent();
intent.setAction("com.cqumonk.adil.calculate");
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_unbind:
unbind();
break;
case R.id.btn_add:
if(mCalculateAIDL!=null){
try {
int res=mAIDL.add(3,3);
txt_res.setText(res+"");
} catch (RemoteException e) {
e.printStackTrace();
}
}else{
Toast.makeText(this,"please rebind",Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_minus:
if(mAIDL!=null){
try {
int res=mAIDL.minus(9,4);
txt_res.setText(res+"");
}catch (RemoteException e) {
e.printStackTrace();
}
}else{
Toast.makeText(this,"please rebind",Toast.LENGTH_SHORT).show();
}
break;
}
}
private ServiceConnection mConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"connect");
binded=true;
mAIDL=MyAIDL.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG,"disconnect");
mAIDL=null;
binded=false;
}
};
}
点击绑定按钮打印出Oncreat onBind connect点击解绑按钮打印出 onUnbind Ondestory
我们并未发现有连接断开的日志打印,这时候,我们继续点击加减法按钮,发现仍然可以完成计算功能,这又是为毛呢?我们看到unbind和destroy的日志打印,说明连接已经断开,service已经被销毁,但是我们返回的stub对象仍然是可以继续使用的。而并不是说service仍然在运行
整个过程的分析如下
首先,我们调用bindservice方法来启动了service:
一方面连接成功时调用了serviceConnection的onServiceConnected方法。我们从该方法中获取到一个Binder对象(注意,这个binder并不是我们在service中实现的那个哦。当service时本apk中的service时,这里返回的是同一个binder),我们通过此binder来与server进行通信。为了区分,我们称为clientBinder。

[code]public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"connect");
binded=true;
mAIDL= MyAIDL.Stub.asInterface(service);
}
另一方面,onBind方法返回了我们实现的Stub对象,其实也是一个Binder,用于和Client进行通信。 (之前我们定义了一个aidl接口文件,并根据它生成了MyAIDL接口。这个接口中有我们定义的两个方法以及一个 静态抽象内部类Stub,它是一个Binder的子类。)我们来看一下Stub是如何定义的:
public static abstract class Stub extends android.os.Binder implements com.cqumonk.calculate.aidl.MyAIDL
它继承了Binder类也实现了MyAIDL接口, 我们实现了定义的add和minus方法。我们仍然要强调一下它并不是clientBinder,在负责与clientBinder进行通信交互的同时,它也维护了service描述符与服务端service的映射。
我们在Client中的onServiceConnected里调用了stub对象的asInterface方法,并将之前得到的clientBinder传入:

public static com.cqumonk.calculate.aidl.MyAIDL asInterface(android.os.IBinder obj) {            if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//根据包名获取本地实现的一个接口的实例,如果是本地service则可以获取到
if (((iin != null) && (iin instanceof com.cqumonk.calculate.aidl.MyAIDL))) {                    return ((com.cqumonk.calculate.aidl.ICalculateAIDL) iin);  //如果得到的实例是ICalculateAIDL的对象,则返回
}
return new com.cqumonk.calculate.aidl.MyAIDL.Stub.Proxy(obj);//如果无法得到本地实现的对象则会返回一个代理对象}
[code]在这个方法中,首先在系统中查找注册的的service,如果没有找到,那么一定是别的apk实现的service,于是返回一个此service的静态代理类对象供Client调用。 我们来看一下这个代理,创建时我们将clientBinder传入了,同时也它实现了MyAIDL接口
private static class Proxy implements com.cqumonk.calculate.aidl.MyAIDL {
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 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);  //调用binderDriver的提供的方法将参数发给服务端
_reply.readException();
_result = _reply.readInt();  //读取到返回结果
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public int minus(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_minus, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
代理中也实现了MyAIDL接口定义的方法,我们以add方法为例,里面将参数打包发送给Server端。在Server端收到请求后,会调用service中我们实现的那个stub对象(mBinder)的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_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_minus: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.minus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
调用完成后把结果打包返回给代理接口处理,最后返回给客户端。总结:由上面的例子我们可以看出,在跨进程通信的时候,Client端使用的代理接口里面封装了一个binder与Server端的stub(也是一个binder对象)进行交互,两个binder作为接口调用BinderDriver的transact来发送数据包,以及onTransact接收处理数据包。如果你感觉有哪些说的不对的地方 请提出来 谢谢 今天就到这 明天给大家分析一下Volley (本人做了7个项目 有四个用的这个框架) 明天给大家详细解析 谢谢[/code][/code]

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: