aidl

来源:互联网 发布:looks for mac 编辑:程序博客网 时间:2024/06/09 22:50
1.aidl,Android Interface Definition Language,即Android接口定义语言。后缀名 .aidl。
  这种语言可以被编译成java语言,即.java文件。
  作用:支持跨进程访问。

2.aidl特点
  1) 识别基本数据类型,不识别对象
  2)不支持public等修饰符关键字
  3)aidl在应用程序之间数据交换,使用了代理机制。

  所以要想让aidl识别对象,要对该类进行处理
  1) 实现Parcelable接口,实现Parcelable接口相应方法。
  2)定义一个该类的aidl描述文件
     定义一个同名的.aidl文件,在文件下添加如下两行代码: 
     package xxx(包名);
     parcelable xxx(类名);
  
3.步骤
  
  进程间传递不包含对象
  1)抽取出接口里面的方法
  2)编写接口
  3)把接口.java文件修改为.aidl文件,删除所有public关键字
  4)把和aidl相关的所有文件拷贝到另一个应用(Activity应用)
  5)编写Service,在清单注册,并且使用<intent-filter>的<action>将自己暴露
     在Service中自定义一个IBinder类,继承Stub即可。
  6)编写Activity。


  进程间传递包含对象
  1)抽取出接口里面的方法
  2)编写接口
  3)编写domain,实现Parcelable接口
  4)编写domain的描述文件 -- .aidl
     定义一个同名的.aidl文件,在文件下添加如下两行代码: 
     package xxx(包名);
     parcelable xxx(类名);
     该文件要和bean在同一个包下
  5)把接口.java文件修改为.aidl文件,删除所有public关键字
  6)把和aidl相关的所有文件拷贝到另一个应用(Activity应用)
  7)编写Service端,在清单注册,并且使用<intent-filter>的<action>将自己暴露
     在Service中自定义一个MyBinder类,继承Stub并且实现方法即可。
     在onBind方法中返回MyBinder对象。
  8)编写Activity端。
     自定义一个类MyServiceConnection实现ServiceConnection,并在onServiceConnected方法中将代理对象转换实际对象。
     使用bindService开启服务,注意intent要设置action。
  


  说明:
  1) 定义一个接口。然后将其后缀名改为.aidl:window->show view->navigator视图下。
  2) 将.aidl中的public关键字删除。aidl不支持public关键字。这时,在gen目录下可以看到会生成一个对应的.java文件
     .java文件中:
     有一个内部类Stub中,Stub中有一个Proxy代理类。有一个asInterface(IBinder)方法。
  3)将Service应用里所有与aidl有关的文件全部复制到Activity应用,注意:要全部相同,包名都要相同。

  4)aidl相当于一份合同,一式两份,Activity一份,Service一份。所以要将所有有关aidl的文件拷贝到Activity应用。

  5)在Activity的内部实现类MyServiceConnection的onServiceConnected方法中:
     如果是其他应用的服务返回IBinder对象,那么该对象是一个代理对象
     将代理对象转换成实际对象
     使用Stub.asInterface(service);方法。

  核心代码:
  Service中:
  //直接继承Stub类
  public class MyBinder extends Stub{}


  Activity中:
  bindService(service, conn, flag);


  onServiceConnected(IBinder service){
//XXX为接口,这一步将代理对象转换成实际对象
XXX ibinder = Stub.asInterface(xxx);
  }
  
4.为什么安卓可以跨进程访问

  aidl <---> IBinder <---> 安卓底层,Linux内核中,添加了自己的Binder Driver,即驱动,它可以实现IPC,即进程间通信。


应用:在一个应用的Activity中获取另一个应用Service的学生姓名。

***************************************************************** 编写Service应用 ****************************************************************

1.编写接口IStudentInter,里面有一个获取学生信息方法。

package com.example.serv.inter;import com.example.serv.domain.Student;public interface IStudentInter {Student getStu(int id);}

2.编写学生bean,该类要实现Parcelable接口并实现方法

public class Student implements Parcelable {public int id;public String name;public Student(int id, String name) {super();this.id = id;this.name = name;}public Student() {super();}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(id);dest.writeString(name);}public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {public Student createFromParcel(Parcel in) {int id = in.readInt();String name = in.readString();Student s = new Student(id, name);return s;}public Student[] newArray(int size) {return new Student[size];}};}

3.在学生bean的包下,编写描述文件Student.aidl

package com.example.serv.domain;parcelable Student;

4.将前面接口的.java文件修改为.aidl文件,并将关键字public删除。可以看到在gen目录下会自动生成一个同名的.java文件

package com.example.serv.inter;import com.example.serv.domain.Student;interface IStudentInter {Student getStu(int id);}

5.编写MyService继承Service,里面编写内部类MyBinder继承Stub,作为进程间传递的对象类

public class MyService extends Service {private String[] names = { "ly", "yl" };private MyBinder binder = new MyBinder();/** * onBind方法返回的IBinder会被客户端接收 */@Overridepublic IBinder onBind(Intent arg0) {return binder;}/** * 内部类,直接继承Stub *  * @author Administrator *  */private class MyBinder extends Stub {@Overridepublic Student getStu(int id) throws RemoteException {Student s = new Student(id, names[id]);return s;}}}

6.在清单中注册service并添加<action>暴露,以便不同应用间访问

        <service android:name="com.example.serv.service.MyService" >            <intent-filter>                <action android:name="com.yp.myservice" />            </intent-filter>        </service>


目录结构



********************************************* 编写Activity应用*********************************************************************************

1.将Service端所有有关aidl的文件拷贝到该应用下,包名要和Service端相同

2.编写Activity,使用bindService开启服务,内部类MyServiceConnection实现ServiceConnection,并在onServiceConnected方法中将代理对象转换成实际对象

public class MainActivity extends Activity {private TextView tv;// binderprivate IStudentInter binder;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);// 开启另一个应用的服务Intent service = new Intent();// 因为是另一个应用的服务,所以要添加actionservice.setAction("com.yp.myservice");MyServiceConnection conn = new MyServiceConnection();bindService(service, conn, Context.BIND_AUTO_CREATE);}/** * 点击按钮获取学生信息 *  * @param v */public void getStuInfo(View v) {try {Student s = binder.getStu(0);tv.setText(s.name);} catch (RemoteException e) {e.printStackTrace();}}/** * 内部类实现ServiceConnection,获取服务端的IBinder *  * @author Administrator *  */private class MyServiceConnection implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 如果是其他应用的服务返回IBinder对象,那么该对象是一个代理对象// 将代理对象转换成实际对象binder = Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {}}}

目录结构




0 0