AIDL简单使用

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.aidl
package com.example.androidipc;

// Declare any non-default types here with import statements
import 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.aidl
package 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值