楼主: 熊猫儿

[转载] 【Android的一些重要知识7。。。。】

[复制链接]
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
61#
 楼主| 发表于 2018-3-2 14:03 | 只看该作者

然后点击12+12,50-12可以成功的调用服务端的代码并返回正确的结果

下面我们再点击unBindService


[html] view plain copy


  • 08-09 22:59:25.567: E/server(29692): onUnbind  
  • 08-09 22:59:25.567: E/server(29692): onDestroy  

由于我们当前只有一个客户端绑定了此Service,所以Service调用了onUnbind和onDestory

然后我们继续点击12+12,50-12,通过上图可以看到,依然可以正确执行,也就是说即使onUnbind被调用,连接也是不会断开的,那么什么时候会端口呢?

即当服务端被异常终止的时候,比如我们现在在手机的正在执行的程序中找到该服务:


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
62#
 楼主| 发表于 2018-3-2 14:09 | 只看该作者

点击停止,此时查看log


[html] view plain copy


  • 08-09 23:04:21.433: E/client(30146): onServiceDisconnected  

可以看到调用了onServiceDisconnected方法,此时连接被断开,现在点击12+12,50-12的按钮,则会弹出Toast服务端断开的提示。

说了这么多,似乎和Binder框架没什么关系,下面我们来具体看一看AIDL为什么做了些什么。

3、分析AIDL生成的代码
1、服务端

先看服务端的代码,可以看到我们服务端提供的服务是由


[java] view plain copy


  • private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()  
  •     {  
  •   
  •         @Override  
  •         public int add(int x, int y) throws RemoteException  
  •         {  
  •             return x + y;  
  •         }  
  •   
  •         @Override  
  •         public int min(int x, int y) throws RemoteException  
  •         {  
  •             return x - y;  
  •         }  
  •   
  •     };  


ICalcAILD.Stub来执行的,让我们来看看Stub这个类的声明:

[java] view plain copy


  • public static abstract class Stub extends android.os.Binder implements com.zhy.calc.aidl.ICalcAIDL  


清楚的看到这个类是Binder的子类,是不是符合我们文章开通所说的服务端其实是一个Binder类的实例

接下来看它的onTransact()方法:


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
63#
 楼主| 发表于 2018-3-2 14:10 | 只看该作者
[java] view plain copy


  • @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_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);  
  • }  http://blog.csdn.net/lmj623565791/article/details/38461079

使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
64#
 楼主| 发表于 2018-3-3 11:59 | 只看该作者
文章开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。

可以看到onTransact有四个参数

code , data ,replay , flags

code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法

data客户端传递过来的参数

replay服务器返回回去的值

flags标明是否有返回值,0为有(双向),1为没有(单向)

我们仔细看case TRANSACTION_min中的代码

data.enforceInterface(DESCRIPTOR);与客户端的writeInterfaceToken对用,标识远程服务的名称

int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();

接下来分别读取了客户端传入的两个参数

int _result = this.min(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);

然后执行this.min,即我们实现的min方法;返回result由reply写回。

add同理,可以看到服务端通过AIDL生成Stub的类,封装了服务端本来需要写的代码。

2、客户端

客户端主要通过ServiceConnected与服务端连接


[java] view plain copy


  • private ServiceConnection mServiceConn = new ServiceConnection()  
  •     {  
  •         @Override  
  •         public void onServiceDisconnected(ComponentName name)  
  •         {  
  •             Log.e("client", "onServiceDisconnected");  
  •             mCalcAidl = null;  
  •         }  
  •   
  •         @Override  
  •         public void onServiceConnected(ComponentName name, IBinder service)  
  •         {  
  •             Log.e("client", "onServiceConnected");  
  •             mCalcAidl = ICalcAIDL.Stub.asInterface(service);  
  •         }  
  •     };  


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
65#
 楼主| 发表于 2018-3-3 12:00 | 只看该作者
如果你比较敏锐,应该会猜到这个onServiceConnected中的IBinder实例,其实就是我们文章开通所说的Binder驱动,也是一个Binder实例

在ICalcAIDL.Stub.asInterface中最终调用了:


[java] view plain copy


  • return new com.zhy.calc.aidl.ICalcAIDL.Stub.Proxy(obj);  


这个Proxy实例传入了我们的Binder驱动,并且封装了我们调用服务端的代码,文章开头说,客户端会通过Binder驱动的transact()方法调用服务端代码

直接看Proxy中的add方法


[java] view plain copy


  • @Override public int add(int x, int y) 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(x);  
  • _data.writeInt(y);  
  • mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);  
  • _reply.readException();  
  • _result = _reply.readInt();  
  • }  
  • finally {  
  • _reply.recycle();  
  • _data.recycle();  
  • }  
  • return _result;  
  • }  


首先声明两个Parcel对象,一个用于传递数据,一个用户接收返回的数据

_data.writeInterfaceToken(DESCRIPTOR);与服务器端的enforceInterfac对应

_data.writeInt(x);
_data.writeInt(y);写入需要传递的参数


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
66#
 楼主| 发表于 2018-3-3 12:00 | 只看该作者

mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);

终于看到了我们的transact方法,第一个对应服务端的code,_data,_repay分别对应服务端的data,reply,0表示是双向的

_reply.readException();
_result = _reply.readInt();

最后读出我们服务端返回的数据,然后return。可以看到和服务端的onTransact基本是一行一行对应的。

到此,我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。

AIDL其实通过我们写的aidl文件,帮助我们生成了一个接口,一个Stub类用于服务端,一个Proxy类用于客户端调用。那么我们是否可以不通过写AIDL来实现远程的通信呢?下面向大家展示如何完全不依赖AIDL来实现客户端与服务端的通信。

4、不依赖AIDL实现程序间通讯
1、服务端代码

我们新建一个CalcPlusService.java用于实现两个数的乘和除


[java] view plain copy


  • package com.example.zhy_binder;  
  •   
  • import android.app.Service;  
  • import android.content.Intent;  
  • import android.os.Binder;  
  • import android.os.IBinder;  
  • import android.os.Parcel;  
  • import android.os.RemoteException;  
  • import android.util.Log;  
  •   
  • 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();  


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
67#
 楼主| 发表于 2018-3-3 12:01 | 只看该作者
  • 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);  
  •         }  
  •   
  •     };  
  •   
  • }  


我们自己实现服务端,所以我们自定义了一个Binder子类,然后复写了其onTransact方法,我们指定服务的标识为CalcPlusService,然后0x110为乘,0x111为除;

使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
68#
 楼主| 发表于 2018-3-3 12:02 | 只看该作者

记得在AndroidMenifest中注册


[html] view plain copy


  • <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>  


服务端代码结束。
2、客户端代码

单独新建了一个项目,代码和上例很类似

首先布局文件:


[html] view plain copy


  • <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"  
  •     androidrientation="vertical" >  
  •   
  •     <Button  
  •         android:layout_width="fill_parent"  
  •         android:layout_height="wrap_content"  
  •         androidnClick="bindService"  
  •         android:text="BindService" />  
  •   
  •     <Button  
  •         android:layout_width="fill_parent"  
  •         android:layout_height="wrap_content"  
  •         androidnClick="unbindService"  
  •         android:text="UnbindService" />  
  •   
  •     <Button  
  •         android:layout_width="fill_parent"  
  •         android:layout_height="wrap_content"  
  •         androidnClick="mulInvoked"  
  •         android:text="50*12" />  
  •       
  •     <Button  
  •         android:layout_width="fill_parent"  
  •         android:layout_height="wrap_content"  
  •         androidnClick="divInvoked"  
  •         android:text="36/12" />  
  •   
  • </LinearLayout>  


可以看到加入了乘和除http://blog.csdn.net/lmj623565791/article/details/38461079

使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
69#
 楼主| 发表于 2018-3-5 08:32 | 只看该作者

然后是Activity的代码


[java] view plain copy


  • package com.example.zhy_binder_client03;  
  •   
  • import android.app.Activity;  
  • import android.content.ComponentName;  
  • import android.content.Context;  
  • import android.content.Intent;  
  • import android.content.ServiceConnection;  
  • import android.os.Bundle;  
  • import android.os.IBinder;  
  • import android.os.RemoteException;  
  • import android.util.Log;  
  • import android.view.View;  
  • import android.widget.Toast;  
  •   
  • 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;  
  •         }  
  •     };  


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
70#
 楼主| 发表于 2018-3-5 08:33 | 只看该作者
  • @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;  

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表