AIDL简介

什么是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 statements

interface 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相比,没有任何优越性了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值