Android实现进程间通信aidl的使用


这两天看了一下Android实现进程间通信binder的实现,在应用层的体现就是aidl的使用。这里也贴一下我参考的文献,
现在总结一下这个用法:
其实很简单,主要就是以下的几个步骤:
1.第一步,定义aidl文件(可以参照IWifiManager.java的定义来实现,其实就是定义一个Interface,提供被调用的方法);
例如 (IMyService.aidl): 
package com.demo; 

import com.demo.Person; 

interface IMyService { 
        void savePersonInfo(in Person person);
//注意,这里的Person类不是基本数据类型哦,要进行处理的,见下文
        List<Person> getAllPerson(); 
}

2.第二步,写一个service,实现stub类(也就是实现刚才的那些接口),return stub类的对象(也就是binder);
    创建一个类实现刚才那个aidl的接口:
public  class RemoteService  extends Service { 

         private LinkedList<Person> personList =  new LinkedList<Person>(); 
         
        @Override 
         public IBinder onBind(Intent intent) { //activity
                 return mBinder; 
        } 

        private final IMyService.Stub mBinder = new IMyService.Stub()

                @Override 
                 public  void savePersonInfo(Person person)  throws RemoteException { 
                         if (person !=  null){ 
                                personList.add(person); 
                        } 
                } 

                @Override 
                 public List<Person> getAllPerson()  throws RemoteException { 
                         return personList; 
                } 
        }; 
}

注:
  这里会看到有一个名为IMyService.Stub类,查看aidl文件生成的Java文件源代码就能发现有这么一段代码:
/** Local-side IPC implementation stub class. */ 
public  static  abstract  class Stub  extends android.os.Binder  implements com.demo.IMyService
  原来Stub类就是继承于Binder类,也就是说RemoteService类和普通的Service类没什么不同,只是所返回的IBinder对象比较特别,是一个实现了AIDL接口的Binder。


3.第三步,在activity里面启动service。
通过IMyService.Stub.asInterface(service)来得到IMyService对象:
private IMyService mRemoteService; 

private ServiceConnection mRemoteConnection =  new ServiceConnection() {    
         public  void onServiceConnected(ComponentName className, IBinder service) {    
                 mRemoteService = IMyService.Stub.asInterface(service);    
        }    

         public  void onServiceDisconnected(ComponentName className) {    
                mRemoteService =  null;    
        }    
};
注:
 在生成的IMyService.java里面会找到这样的代码:
/** 
* Cast an IBinder object into an com.demo.IMyService interface, 
* generating a proxy if needed. 
*/
 
public  static com.demo.IMyService asInterface(android.os.IBinder obj) {...}


而service的绑定没有什么不同:
if (mIsRemoteBound) { 
        unbindService(mRemoteConnection); 
} else
        bindService( new Intent( "com.demo.IMyService"), 
                                mRemoteConnection, Context.BIND_AUTO_CREATE); 


mIsRemoteBound = !mIsRemoteBound;
 
通过IPC调用/传递数据
    客户端绑定service后就能通过IPC来调用/传递数据了,直接调用service对象的接口方法:
addPersonButton.setOnClickListener( 
                 new View.OnClickListener(){ 
                         private  int index = 0; 

                        @Override 
                         public  void onClick(View view) { 
                                Person person =  new Person(); 
                                index = index + 1; 
                                person.setName( "Person" + index); 
                                person.setAge(20); 
                                person.setTelNumber( "123456"); 
                                try { 
                                        mRemoteService.savePersonInfo(person); 
                                } catch (RemoteException e) { 
                                        e.printStackTrace(); 
                                } 
                        } 
                }); 

listPersonButton.setOnClickListener( 
                 new View.OnClickListener(){ 

                        @Override 
                         public  void onClick(View view) { 
                                List<Person> list =  null

                                try { 
                                        list = mRemoteService.getAllPerson(); 
                                } catch (RemoteException e) { 
                                        e.printStackTrace(); 
                                } 

                                 if (list !=  null){ 
                                        StringBuilder text =  new StringBuilder(); 

                                         for(Person person : list){ 
                                                text.append( "\nPerson name:"); 
                                                text.append(person.getName()); 
                                                text.append( "\n             age :"); 
                                                text.append(person.getAge()); 
                                                text.append( "\n tel number:"); 
                                                text.append(person.getTelNumber()); 
                                        } 

                                        inputPersonEdit.setText(text); 
                                } else { 
                                        Toast.makeText(ServiceActivity. this"get data error"
                                                        Toast.LENGTH_SHORT).show(); 
                                } 
                        } 
                });



另外关于第一步,附加的说一下。当aidl中的接口中的返回值或参数不是基本数据类型时,需要做如下的两步:
1.给一个aidle的实现:
package com.demo; 

parcelable Person;
 2.给一个序列化(实现java类)
public  class Person  implements Parcelable { 

         private String name; 
         private String telNumber; 
         private  int age; 

         public Person() {} 

        public Person(Parcel pl){ 
                name = pl.readString(); 
                telNumber = pl.readString(); 
                age = pl.readInt(); 
        } 

         public String getName() { 
                 return name; 
        } 

         public  void setName(String name) { 
                 this.name = name; 
        } 

         public String getTelNumber() { 
                 return telNumber; 
        } 

         public  void setTelNumber(String telNumber) { 
                 this.telNumber = telNumber; 
        } 

         public  int getAge() { 
                 return age; 
        } 

         public  void setAge( int age) { 
                 this.age = age; 
        } 

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

        @Override 
        public void writeToParcel(Parcel dest, int flags) { 
                dest.writeString(name); 
                dest.writeString(telNumber); 
                dest.writeInt(age); 
        } 

        public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() 

                @Override 
                 public Person createFromParcel(Parcel source) { 
                         return new Person(source); 
                } 

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

        }; 
}

Parcelable需要实现三个函数:
    1) void writeToParcel(Parcel dest, int flags) 将需要序列化存储的数据写入外部提供的Parcel对象dest。而看了网上的代码例子,个人猜测,读取Parcel数据的次序要和这里的write次序一致,否则可能会读错数据。具体情况我没试验过!
    2) describeContents() 没搞懂有什么用,反正直接返回0也可以
    3) static final Parcelable.Creator对象CREATOR  这个CREATOR命名是固定的,而它对应的接口有两个方法:
    createFromParcel(Parcel source) 实现从source创建出JavaBean实例的功能
    newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话(return new T[size])即可。估计本方法是供外部类反序列化本类数组使用。


至此,就ok啦~微笑

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值