AIDL简介

来源:互联网 发布:天猫旗舰店的流量数据 编辑:程序博客网 时间:2024/06/05 03:42

什么是AIDL

AIDL是Android Interface Definition Language的缩写,是android 为进程间服务访问提供的对外接口定义。

什么情况下使用AIDL

Android官方文档给出了使用场景。

Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.

仅用于“外部进程想访问你的Service”且“你的Service具有多线程特性”的情况下。
单进程中的Service,Binder足够满足要求,它支持多线程。跨进程的单线程,可使用Message。

如何使用AIDL

(1)创建AIDL目录

这里写图片描述

(2)创建一个名为IPerso的AIDL文件

这里写图片描述

AS自动生成代码如下

package com.breakloop.aidlservice;// Declare any non-default types here with import statementsinterface IPerso {    /**     * 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);}

AIDL虽然跟JAVA的Interface结构很像,并非使用JAVA语法。
AS所生成的代码,并没有什么实际的用处,只是告诉coder,AIDL所支持的基本类型有哪些。

(3)设计两个方法

package com.breakloop.aidlservice;interface IPerso {    int getAge();    String getName();}

特别注意,编写完AIDL文件后,需要Rebuild Project,否则在实现IPerso接口时,将无法找到IPerso.Stub类。

(4)实现IPerso接口

定义一个Perso类,继承自IPerso.Stub。

public class Perso extends IPerso.Stub {    @Override    public int getAge() throws RemoteException {        return 1;    }    @Override    public String getName() throws RemoteException {        return "breakloop";    }}

(5)返回IPerso接口实例

创建自定义Service,并在onBind中返回Perso实例。

public class PersoInfo extends Service {    private Perso mPerso;    public PersoInfo() {        mPerso=new Perso();    }    @Override    public IBinder onBind(Intent intent) {        return mPerso;    }}

(6)Remote App使用AIDL
在Remote App中创建AIDL目录,并将IPerso.AIDL文件复制至该目录中。

这里写图片描述

这里写图片描述

确保AIDL文件的一致性,非常重要。很多问题是由于AIDL不一致造成的。

(7)Remote App获取接口实例

public class MainActivity extends AppCompatActivity {    private ServiceConnection mServiceConnection;    private IPerso mPerso;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mServiceConnection=new ServiceConnection() {            @Override            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {                mPerso=IPerso.Stub.asInterface(iBinder);                try {                    int age =mPerso.getAge();                    String  name=mPerso.getName();                    String content="Name = "+name+"Age = "+age;                    Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();                    Log.i(getClass().getName(), "onServiceConnected: "+content);                } catch (RemoteException e) {                    e.printStackTrace();                }            }            @Override            public void onServiceDisconnected(ComponentName componentName) {            }        };        Intent intent=new Intent("android.intent.action.PERSO");        intent.setPackage("com.breakloop.aidlservice");        bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);    }}

重点强调,mPerso=IPerso.Stub.asInterface(iBinder); 将Binder转换为了IPerso实体类。

至此,AIDL调用完成。但并没有结束!问题来了:如果用到了自定义类呢?

AIDL中使用自定义类

(1)创建自定义类BankCard

public class BankCard{    public String mCardID;    public int mAmount;    public BankCard(){    }}

(2)BankCard实现序列化

public class BankCard implements Parcelable{    public String mCardID;    public int mAmount;    public BankCard(){    }    @Override    public int describeContents() {        return 0;    }    public static final Parcelable.Creator<BankCard> CREATOR = new Parcelable.Creator<BankCard>()    {        public BankCard createFromParcel(Parcel in)        {            return new BankCard(in);        }        public BankCard[] newArray(int size)        {            return new BankCard[size];        }    };    @Override    public void writeToParcel(Parcel parcel, int i) {        parcel.writeInt(mAmount);        parcel.writeString(mCardID);    }    private BankCard(Parcel in)    {        mAmount = in.readInt();        mCardID=in.readString();    }}

(3)创建BankCard AIDL
这里需要注意两点
(a)AIDL文件名与自定义类名一致!!!
(b)AIDL中只需要包括两行信息,Package和序列化的类名。”parcelable”一定是小写!!!
AIDL文件内容如下

package com.breakloop.aidlservice;parcelable BankCard;

重新编译或同步工程!让工程察觉到BankCard的存在!!

(4)在IPerso.AIDL中引用BankCard类,并添加获取BankCard类的接口

package com.breakloop.aidlservice;import com.breakloop.aidlservice.BankCard;interface IPerso {    int getAge();    String getName();    BankCard getCard();}

(5)将BankCard类和BankCard.AIDL拷贝至Remote App
需要注意的是,package名称必须一致。

这里写图片描述

重新编译或同步工程!!!!!让工程更新接口!!!

(6)Remote App获取接口实例

@Override            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {                mPerso=IPerso.Stub.asInterface(iBinder);                try {                    int age =mPerso.getAge();                    String  name=mPerso.getName();                    BankCard card=mPerso.getCard();                    String content="Name = "+name+"Age = "+age+" CardNum = "+card.mCardID+" Amount = "+card.mAmount;                    Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();                    Log.i(getClass().getName(), "onServiceConnected: "+content);                } catch (RemoteException e) {                    e.printStackTrace();                }            }

至此自定义类调用成功。

但通常自定义类使用的较少。在提供IADL的同时,再输出自定义类,会将release变得更加复杂,增加出错的可能性。跟输出SDK相比,没有任何优越性了。

原创粉丝点击