AIDL(初解)

1.什么是AIDL:
AIDL(Android Interface Define Language)是Android接口定义语言。Android系统中进程之间不是实现内存共享,所以需要一些机制在进程之间实现数据的通信。IPC进程间通信方式的一种,用于生成可以在安卓设备上两个进程之间进行进程间通信(interprocess communication)的代码。
Binder:Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式。通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,
2.举例
2-1 创建AIDL文件

interface MyAIDL {

    //自定义的函数
    int add (int num1,int num2);
}

2-2 在Build->generated->source->aidl->debug下生成相应的.java文件。


public interface MyAIDL extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
/*声明一个内部类Stub,就是一个Binder类;当客户端和服务端在同一进程时,方法的调用不会走跨进程的transact过程,当两者不在同一进程时候,方法的调用需要走transact过程,这个逻辑由内部代理类Proxy完成。
*/
public static abstract class Stub extends android.os.Binder implements com.sbl.aidltest.MyAIDL
{
private static final java.lang.String DESCRIPTOR = "com.sbl.aidltest.MyAIDL";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.sbl.aidltest.MyAIDL interface,
 * generating a proxy if needed.
 */

 /*将服务端的Binder对象转换成客户需要的AIDL对象,转换区分进程,客户端服务端位于同一进程,返回服务端的Stub对象本身;否则返回的是系统的封装后的Stub.proxy对象。
 */
public static com.sbl.aidltest.MyAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.sbl.aidltest.MyAIDL))) {
return ((com.sbl.aidltest.MyAIDL)iin);
}
return new com.sbl.aidltest.MyAIDL.Stub.Proxy(obj);
}
//返回当前Binder对象
@Override public android.os.IBinder asBinder()
{
return this;
}
/*运行在服务端的Binder线程池中。远程进程Binder对象执行完成后,将得到的 写入自己的共享内存中,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_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
//读取客户端传递过来在data中存储的信息
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
//将结果信息写入reply中,
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
//代理类,运行在客户端
private static class Proxy implements com.sbl.aidltest.MyAIDL
{
//声明一个IBinder对象
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
 //返回当前IBinder对象
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}

//客户端调用此方法,传递相应的参数
@Override public int add(int num1, int num2) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
//向_data中写入参数
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(num1);
_data.writeInt(num2);
/*在调用所持有的Binder引用的transact()函数,transact函数执行过程中会把参数、标识符(标记远程对象及其函数)等数据放入到Client的共享内存,Binder驱动从Client的共享内存中读取数据,根据这些数据找到对应的远程进程的共享内存,把数据拷贝到远程进程的共享内存中,并通知远程进程执行onTransact()函数,这个函数也是属于Binder类
*/
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
//唯一标识
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}

public int add(int num1, int num2) throws android.os.RemoteException;
}

2-3 代码中的几个方法:
DESCRIPTOR(描述符)
Binder的唯一标识,一般用当前的Binder类名表示。
asInterface(android.os.IBinder obj)
用于将服务端的Binder对象转换为客户端需要的AIDL接口类型的对象,转换区分进程,客户端服务端位于同一进程,返回服务端的Stub对象本身;否则返回的是系统的封装后的Stub.proxy对象。
asBInder
返回Binder对象
onTransact
此方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。需要注意的是,onTransact返回的是boolean型变量,那么如果返回的是false,则 客户端的请求失败,因此可以运用这个特性做权限的限制。
Proxy#add
此方法运行在客户端,当客户端远程调用此方法时,它的内部实现是这样的:首先创建该方法所需要的输入型Parcel对象_data、输出型Parcel对象_reple和返回值对象_result,然后将该方法的参数信息写入_data中;接着调用transact方法来发RPC请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程返回的结果,写入_result中。
2-4. 在服务端(另外一个进程)创建一个Service用来监听客户端的连接请求。

public class ProgressService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return iBinder;
    }

    private IBinder iBinder = new MyAIDL.Stub(){
 /*这是运行在服务器(另一个线程中的),逻辑代码处理的主要部分。this.add()方法调用了这个函数,然后得到结果,再把结果给了客户端(另外一个进程) 
 */
        @Override
        public int add(int num1, int num2) throws RemoteException {
           //返回结果
            return num1 + num2;
        }
    };

}

2-5 清单文件中注册ProgressService

    <service android:name=".ProgressService"
        android:process=":remote">
    </service>

:remote中的冒号含义是在当前的进程名前面附加上当前的包名,这是一种简单的写法。
2-6 MainActivity

public class MainActivity extends AppCompatActivity  {
    private EditText editTextNum1;
    private EditText editTextNum2;
    private Button button;
    private TextView textViewResult;

    private  MyAIDL myAIDL;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
    //将服务端(另外一个进程)的Binder对象转化成客户端需要的AIDL接口对象
           myAIDL = MyAIDL.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myAIDL =null;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_two);

        bindService();
        initView();

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int   num11 = Integer.parseInt(editTextNum1.getText().toString());
                int   num22 = Integer.parseInt(editTextNum2.getText().toString());
                try {
                    int res = myAIDL.add(num11,num22);
                    textViewResult.setText( res+"");
                } catch (RemoteException e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
    private void initView() {
        editTextNum1 = (EditText) findViewById(R.id.et_num1);
        editTextNum2 = (EditText) findViewById(R.id.et_num2);
        button = (Button) findViewById(R.id.bt_add);
        textViewResult = (TextView) findViewById(R.id.tv_result);
    }

    private void bindService() {
        Intent intent = new Intent(this,ProgressService.class);
        bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
    }

        @Override
        protected void onDestroy()
        {
            super.onDestroy();
            unbindService(serviceConnection);
        }


}

注意: textViewResult.setText( res+”“)
如果直接将一个int类型 的数据setText,默认的回去寻找资源文件,当然不存在,会报 android.content.res.Resources$NotFoundException: String resource ID #0xa错误,所以需要转化成字符串类型。

附:服务端跨进程的类都要继承Binder类。我们所持有的Binder引用(即服务端的类引用)并不是实际真实的远程Binder对象,我们的引用在Binder驱动里还要做一次映射。也就是说,设备驱动根据我们的引用对象找到对应的远程进程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值