AIDL简单使用

来源:互联网 发布:java 正态分布随机数 编辑:程序博客网 时间:2024/06/05 03:47

AIDL(Android Interface Definition Language),Android接口定义语言。一般利用AIDL来进行进程间通信,大概流程如下:

1、服务端进程创建一个Service,供客户端进程来连接,通过创建AIDL文件定义好接口,然后Android Studio会自动帮我们生成对应AIDL的.java文件,然后服务端实现接口里的方法,并在onBind方法中返回自定义Binder对象,Binder相当于是服务端和客户端通信的桥梁。

2、客户端需要把服务端的AIDL文件复制到客户端app的工程下,切记包名也要一样,如果在调用AIDL的方法中使用到了自定义的类,也一样需要把该类的.java文件一并复制过来,同样,包名也必须一致,有了服务端的AIDL文件,我们只需要绑定服务端的Service,在绑定成功后,拿到服务端onBind方法返回的Binder对象进行一下转换,就能调用服务端实现的方法了。这样就实现了两个进程间的通信。


接下来看具体实现(为了方便,在同一个app中让Service运行在另外一个进程中,然后通过主进程去和该Service通信,这和两个app之间的通信实质上是一样的,只是省去了复制AIDL文件和自定义类文件了):

这里使用Android Studio来编写,右键->新建一个名为IPersonService的AIDL,这时IDE会自动帮我们在main包下建立一个aidl的包,里面放着刚才IPersonService.aidl文件:

// IPersonService.aidlpackage com.example.androidipc;// Declare any non-default types here with import statementsimport com.example.androidipc.Person;interface IPersonService {    List<Person> getPerson();    void addPerson(in Person p);}
IPersonService.aidl中声明了两个方法,getPerson获取所有person list,addPerson往集合中添加一个person对象,在addPerson方法的参数前面有一个in,是说明我们这个参数是属于输入型的。再看看Person.aidl:

// Person.aidlpackage com.example.androidipc;parcelable Person;
Person对应的.java文件:

package com.example.androidipc;import android.os.Parcel;import android.os.Parcelable;/** * Created by Rainbow556 on 11/22/2015. */public class Person implements Parcelable{    private String name;    private int age;    public Person(String name,int age){        this.name=name;        this.age=age;    }    protected Person(Parcel in) {        name=in.readString();        age=in.readInt();    }    public static final Creator<Person> CREATOR = new Creator<Person>() {        @Override        public Person createFromParcel(Parcel in) {            return new Person(in);        }        @Override        public Person[] newArray(int size) {            return new Person[size];        }    };    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(name);        dest.writeInt(age);    }    @Override    public String toString() {        return name+" , "+age;    }    public String getName() {        return name;    }}
上一篇博客说过,支持跨进程传输的类型只有基本数据类型和Android中特定的某些类,如果要传输自定义类的话,这个类必须要实现Parcelable接口。

下面是工程结构:


有一点要注意,就算IPersonService和Person位于同一个包下,但在IPersonService中还是要显示的导入Person类,否则会提示找不到类。

接着看Service的代码:

public class PersonService extends Service {    private List<Person> persons=new ArrayList<>();    public PersonService() {    }    @Override    public void onCreate() {        super.onCreate();        Person p=null;        for (int i=0;i<3;i++){            p=new Person("lx"+i,18+i);            persons.add(p);        }    }    @Override    public IBinder onBind(Intent intent) {        return new PersonBinder();    }    public class PersonBinder extends IPersonService.Stub{        @Override        public List<Person> getPerson() throws RemoteException {            return persons;        }        @Override        public void addPerson(Person person) throws RemoteException {            persons.add(person);        }        @Override        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {//            String packageName = null;//            //拿到调用者的包名,可以做权限验证//            String[] packages = PersonService.this.getPackageManager().//                    getPackagesForUid(getCallingUid());//            if (packages != null && packages.length > 0) {//                packageName = packages[0];//            }//            if (!ALLOW_PACKAGE.equals(packageName)) {//                return false;//            }            return super.onTransact(code, data, reply, flags);        }    }}
可以看到在Service中自定义个了PersonBinder继承了IPersonService.Stub,并重写了三个方法,注意一下onTransact方法,在这个方中可以对调用者进行自定义的权限验证,如果返回false,则调用者会调用失败。

再看activity中绑定Service,调用aidl中的方法:

public class AIDLActivity extends Activity {    IPersonService mService;    TextView tv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_aidl);        ServiceConnection mServiceConnection=new ServiceConnection() {            @Override            public void onServiceConnected(ComponentName name, IBinder service) {                mService = IPersonService.Stub.asInterface(service);            }            @Override            public void onServiceDisconnected(ComponentName name) {            }        };        Intent i=new Intent(this,PersonService.class);        bindService(i,mServiceConnection,BIND_AUTO_CREATE);        tv = (TextView) findViewById(R.id.tv);    }    public void getPersonList(View v){        try {            tv.setText(mService.getPerson().toString());        } catch (RemoteException e) {            e.printStackTrace();        }    }    public void addPerson(View v){        Person p=new Person("lj",22);        try {            mService.addPerson(p);            tv.setText(mService.getPerson().toString());        } catch (RemoteException e) {            e.printStackTrace();        }    }}
在activity中建立一个ServiceConnection,去绑定服务,在绑定成功后调用IPersonService.Stub.asInterface方法把传递过来的IBinder转换成IPersonService对象,这样就可以调用服务端aidl中的方法了,大概流程就是这样。



0 0