AIDL 跨进程通信方式,的基本使用和源码理解

第一部分

使用的AIDL文件的方法:

AIDL接口文件的处理:  

   在客户端将AIDL文件拷贝到自己的工程中:

    1.main 文件夹下建立aidl文件夹.将AIDL文件复制进去,如果是引入已经写好的aidl文件,那么包就应该是该aidl文件中的包名(切记!)并把提供的aidl文件复制到下面

    2.rebuild后 在build/generated/source/aidl/debug下就可以见到自动生成的Java文件

绑定服务:

  Intent intent =new Intent();
        intent.setAction("com.cuizehui.ADD");// service 文件要声明意图  5.0后要设置包名!
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
成功后,获取Binder:

  private ServiceConnection conn=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mservice =  MytestAIDL.Stub.asInterface(service);
            //这个就是我们获取的Binder!!!!!!!接下来就可以用它操作远程服务了!

            Log.d("绑定远程服务","成功");
        }
         //这个方法只有在 服务被收回等异常时才会调用,如果服务不存在,则不会调用
        @Override
        public void onServiceDisconnected(ComponentName name) {
         Log.d("绑定失败","失败");
        }
    };

如果服务不存在的话可以通过

bindservice 的返回值进行判断 是否存在

创建远程服务并生成AIDL文件的方法:

生成AIDL文件: 

(要便称AIDL文件就是接口文件。) 那么android studio 中怎么搞呢?

   1.android studio 中就直接new aidl 文件就好啦 !然后把接口方法添加一下像这样:

// MytestAIDL.aidl
package com.example.cuizehui.aidlfarservice;

// Declare any non-default types here with import statements

interface MytestAIDL {


    int add(int x,int y);
}

rebuild .即可看到

在build/generated/source/aidl/debug下就可以见到自动生成的Java文件.这个生成的java文件。给我们自动生成了一个内部类:

package com.example.cuizehui.aidlfarservice;
// Declare any non-default types here with import statements

public interface MytestAIDL extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.cuizehui.aidlfarservice.MytestAIDL
{
private static final java.lang.String DESCRIPTOR = "com.example.cuizehui.aidlfarservice.MytestAIDL";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.cuizehui.aidlfarservice.MytestAIDL interface,
 * generating a proxy if needed.
 */
public static com.example.cuizehui.aidlfarservice.MytestAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.cuizehui.aidlfarservice.MytestAIDL))) {
return ((com.example.cuizehui.aidlfarservice.MytestAIDL)iin);
}
return new com.example.cuizehui.aidlfarservice.MytestAIDL.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_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;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.cuizehui.aidlfarservice.MytestAIDL
{
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 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;
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int add(int x, int y) throws android.os.RemoteException;
}

创建远程服务: 

1.修改Onbind方法 返回远程的IBinder对象:

  @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return   new MiddlePerson();
    }

2.还要把binder 的继承也给改了 . 就是本地服务的Binder,正常的话本地服务是要继承binder类并实现方法接口的。

     但是AIDL 生成的java文件 已经继承了binder ,并且实现了上面接口文件的接口类型。。棒棒哒。。所以直接修改继承这个内部类,并实现方法就好啦!

     内部类的名字就是AIDL文件的名字.stub (请看上面源码)

public class RomateService extends Service {
    public RomateService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return   new MiddlePerson();
    }

    private class MiddlePerson extends MytestAIDL.Stub{


        @Override
        public int add(int x, int y) throws RemoteException {
            return  x+y;
        }
    }
}

3.不要忘记了销毁时处理标记等。

时至今时: 就写好远程服务啦。

第二部分

AIDL 监听器处理:

   //业务场景:
    /**
     * 客户端给服务端一个监听,并写了具体的监听方法。(监听数据更新了没)
     * 服务端拿到了这个监听器后,当自己的数据更新了,就执行监听器内的方法。这是就是观察者模式。
     */

服务端AIDL修改:

注意:

   AIDL 中的接口类型也必须为AIDL类型的。不允许定义普通接口。

// MytestAIDL.aidl
package com.example.cuizehui.aidlfarservice;
import com.example.cuizehui.aidlfarservice.IOnArrivedListenter ;
// Declare any non-default types here with import statements
interface MytestAIDL {
    //远程服务的方法
    int add(int x,int y);
    //绑定监听
    void registerListener(IOnArrivedListenter  listner);
    //解绑监听
    void unregisterListener(IOnArrivedListenter  listner);
}

注意导包!问题!!

定义的接口:

// IOnArrivedListenter.aidl
package com.example.cuizehui.aidlfarservice;

// Declare any non-default types here with import statements

interface IOnArrivedListenter {
   void onNewArrived();
}

服务端对于监听器的逻辑处理:

保证线程同步存放多个监听的容器:

由于可能有很多监听器,所以这里我们提供一个List来存储 客户端的监听器s。

    //binder 本来是线程不同步的, 这里我们使用CopyOnWriteArrayList来进行自动的线程同步。这样做的目的是可能有许多个监听都注册了

     private CopyOnWriteArrayList<IOnArrivedListenter> mListenerList=new CopyOnWriteArrayList<IOnArrivedListenter>();

注册:

   @Override
        public void registerListener(IOnArrivedListenter listner) throws RemoteException {
            if(!mListenerList.contains(listner)){
                if(listner!=null){
                    mListenerList.add(listner);
                }
                else {
                    Log.d("传过来的监听器就是空的","!");
                }

            }
            else {
                Log.d("tag","已经存在了");
            }
        }

执行监听器中的方法:

    //当有数据更新后就执行这个方法。
    //当绑定成功后 还是需要调用接口中方法,这时通过Listenerlist 中的Listener 调用接口内方法
    private  void onNewArrived() throws RemoteException {
        Log.d("绑定监听器的个数",""+mListenerList.size());
        //下面才是调用的接口方法。
        for(int i=0 ;i<mListenerList.size();i++){
            Log.d("绑定监听器的个数",""+mListenerList.size());
            IOnArrivedListenter listenter = mListenerList.get(i);
            //调用接口的方法 这个方法是在客户端实现的!
            listenter.onNewArrived();

        }

    }
可是实现同步并解注的容器:

但是注意上面这种方式不能完成解注:

原理:

       因为是序列化 和反序列化的过程,所以 不是同一个对象。 引入一个新的类

       RemoteCallbackList,但是这个类并不是list 必须按照他的方式遍历(beginBroadcast, finishBroadcast)配对使用

       这个类底层是一个MAP  存放类 IBinder 和对应的Callback.


使用方式: 用这类类代替上面这个CopyOnWriteArrayList

    private RemoteCallbackList<IOnArrivedListenter> mListenerList=new RemoteCallbackList<IOnArrivedListenter>();
  

修改,register 和unregistListener 两个方法 很简单。

   public void registerListener(IOnArrivedListenter listner) throws RemoteException {
            mListenerList.register(listner);
        }

        @Override
        public void unregisterListener(IOnArrivedListenter listner) throws RemoteException {
           mListenerList.unregister(listner);
        }


    }

当要调用listener 中的监听方法时,这样处理

final  int N=mListenerList.beginBroadcast();
        for(int i=0; i<N;i++){
            IOnArrivedListenter l = mListenerList.getBroadcastItem(i);
            if(l!=null){
                try {
                    l.onNewArrived();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            
        }
        mListenerList.finishBroadcast();
        


客户端注册监听使用:

1实现监听器(注意还是AIDL文件接口内部类 的实现)

  private IOnArrivedListenter listener=new IOnArrivedListenter.Stub(){

        @Override
        public void onNewArrived() throws RemoteException {
            Log.d("执行客户端的监听方法","!");
        }
    };
2.
        mservice.registerListener(listener);
                     
3.在这之前的AIDL文件还是要生成java文件的就不讲了。


服务死亡代理:

另细节注意:

当服务端死亡时,客户端并不知道,这时如何处理?

原理:Binder这两个方法linkToDeath 和unlinkToDeath方法 设置死亡代理。

给服务端设置死亡代理,本质也就是上文的监听者模式吧。当监听器监听到服务死亡。设置重新连接。

实现方式:

1.在客户端中声明IBinder类DeathRecipient对象,是IBinder类的一个接口:

//实现IBinder类中提供的死亡代理的接口
    private  IBinder.DeathRecipient mDeathRecipent=new IBinder.DeathRecipient(){

        @Override
        public void binderDied() {
              if(mservice==null)
                return;
                mservice.asBinder().unlinkToDeath(mDeathRecipent,0);
                mservice=null;
              //如果
        }
    };
这里的mService就是我们返回的IBinder. 代码的意思是如果他死亡了 那么我们重新连接。

2.绑定时同时设置死亡代理,

  mservice =  MytestAIDL.Stub.asInterface(service);
            //设置死亡代理!
            try {
                service.linkToDeath(mDeathRecipent,0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

传输序列化对象:

三步:

1实现序列化:

package com.example.cuizehui.estoredataservice;

import android.os.Parcel;
import android.os.Parcelable;

import org.litepal.crud.DataSupport;

/**
 * Created by cuizehui on 17-9-19.
 */

public class ShopDaTa extends DataSupport implements Parcelable {
    //详细图片地址
    String  picadress;
    //商品描述
    String  productdic;
    //商店名
    String shopName;
    //店铺名
    String  productName;
    //缩略图地址
    String  picsmalladress;
    //商品价格
    String price;
    //快递价格
    String mailprice;
    //图片字节数组
    byte[] bitmaps ;

    byte[] bitmapbig ;

    protected ShopDaTa(Parcel in) {
        picadress = in.readString();
        productdic = in.readString();
        shopName = in.readString();
        productName = in.readString();
        picsmalladress = in.readString();
        price = in.readString();
        mailprice = in.readString();
        bitmaps = in.createByteArray();
        bitmapbig = in.createByteArray();
    }

    public static final Creator<ShopDaTa> CREATOR = new Creator<ShopDaTa>() {
        @Override
        public ShopDaTa createFromParcel(Parcel in) {
            return new ShopDaTa(in);
        }

        @Override
        public ShopDaTa[] newArray(int size) {
            return new ShopDaTa[size];
        }
    };

    public byte[] getBitmaps() {
        return bitmaps;
    }

    public void setBitmaps(byte[] bitmaps) {
        this.bitmaps = bitmaps;
    }

    public byte[] getBitmapbig() {
        return bitmapbig;
    }

    public void setBitmapbig(byte[] bitmapbig) {
        this.bitmapbig = bitmapbig;
    }

    public ShopDaTa() {
    }









    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public String getPicadress() {
        return picadress;
    }

    public void setPicadress(String picadress) {
        this.picadress = picadress;
    }

    public String getProductdic() {
        return productdic;
    }

    public void setProductdic(String productdic) {
        this.productdic = productdic;
    }

    public String getPicsmalladress() {
        return picsmalladress;
    }

    public void setPicsmalladress(String picsmalladress) {
        this.picsmalladress = picsmalladress;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getMailprice() {
        return mailprice;
    }

    public void setMailprice(String mailprice) {
        this.mailprice = mailprice;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(picadress);
        parcel.writeString(productdic);
        parcel.writeString(shopName);
        parcel.writeString(productName);
        parcel.writeString(picsmalladress);
        parcel.writeString(price);
        parcel.writeString(mailprice);
        parcel.writeByteArray(bitmaps);
        parcel.writeByteArray(bitmapbig);
    }
}



特别注意:包名路径 和 Java文件相同, 文件名 就是Java文件名.aidl.  出现同名文件无法创建情况,先填别的然后修改

3.在要远程调用对象的AIDL中 导包

// IDataAidlInterface.aidl
package com.example.cuizehui.estoredataservice;

// Declare any non-default types here with import statements
import com.example.cuizehui.estoredataservice.ShopDaTa;


interface IDataAidlInterface {
    /**
     * 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);

        List<ShopDaTa> getShopDaTaList();


}


注意最好和数据aidl 文件在一个包下,并且 注意路径问题!


获取字节数据:

 public void  provideServiceData(){
        //调用远程服务
        Intent intent =new Intent();
        intent.setAction("com.cuizehui.dataservice");
        intent.setPackage("com.example.cuizehui.estoredataservice");
        mainActivity.bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                mservice = IDataAidlInterface.Stub.asInterface(iBinder);

                //操作远程服务


                List<com.example.cuizehui.estoredataservice.ShopDaTa> shopDaTas;
                try {
                    shopDaTas=mservice.getShopDaTaList();

                    ArrayList<ShopDaTa> arrayList=new ArrayList<>();

                    for (int i=0;i<shopDaTas.size();i++){

                        ShopDaTa shopDaTa=new ShopDaTa();
                        shopDaTa.setPicadress(shopDaTas.get(i).getPicadress());
                        shopDaTa.setPrice(shopDaTas.get(i).getPrice());
                        shopDaTa.setProductName(shopDaTas.get(i).getProductName());
                        shopDaTa.setShopName(shopDaTas.get(i).getShopName());
                        shopDaTa.setProductdic(shopDaTas.get(i).getProductdic());
                        shopDaTa.setMailprice(shopDaTas.get(i).getMailprice());
                         byte[] bytes;
                        if(shopDaTas.get(i).getBitmaps()!=null){
                             bytes=shopDaTas.get(i).getBitmaps();
                            Log.d("bitmap_log",bytes.length+"!null");
                            shopDaTa.setBitmaps(bytes);
                        }
                        else {
                            Log.d("bitmap","null");
                        }
                        Log.d("context",shopDaTas.get(i).getProductName()+"");
                        arrayList.add(shopDaTa);

                    }
                    homeViewpagerLVAdapter1=new HomeViewpagerLVAdapter(arrayList,mainActivity);

                    Toast.makeText(mainActivity,shopDaTas.size()+""+":"+arrayList.size(),Toast.LENGTH_SHORT).show();


                    //refrush
                    initView();
                    initEvent();

                } catch (RemoteException e) {
                    e.printStackTrace();
                }

                Log.d("绑定远程服务","成功");

            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                Log.d("绑定失败","失败");
            }
        }, mainActivity.BIND_AUTO_CREATE);

    }



实现的机制:


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值