android--service之aidl传递复杂对象,Android回顾--(二十四) AIDL的简单以及传递复杂数据...

AIDL:

一种接口定义语言来公开服务的接口,跨进程访问的服务

建立AIDL服务的步骤:

服务端的实现

在Java源文件目录下建立一个aidl文件,直接通过点击new创建aidl文件,Android Studio会自动帮你新建aidl包。具体位置如图:

d9e3b4d4361a

aidl文件位置.png

// UserInfo.aidl

package com.ting.android.aidldemo;

// Declare any non-default types here with import statements

interface UserInfo {

String getInfo();

}

aidl文件的内容与Java代码非常相似,但是要注意,不能加任何权限修饰符,AIDL不支持的数据类型。

如果UserInfo.aidl文件中的内容输入正确,我们rebuild项目,ADT会自动生成一个UserInfo.java文件,我们开发中不需要关注这个文件的内容。

编写一个Service类,MyAidlServletService类继承于Service,在MyAidlServletService类中定义了一个内部类(MyBinder),该类继承自UserInfo.Stub。

public class MyAidlServletService extends Service {

public class MyBinder extends UserInfo.Stub{

@Override

public String getInfo() throws RemoteException {

return "这里是服务端返回的信息";

}

}

public MyAidlServletService() {

}

@Override

public IBinder onBind(Intent intent) {

return new MyBinder(); //这里一定要返回内部类的对象

}

}

UserInfo.Stub是自动生成的,不需要关注。只需要继承之后,实现要调用的方法即可。在onBind方法中必须返回内部类的对象,否则客户端无法获取服务对象

在AndroidMainifest.xml文件中配置MyAidlServletService类。

android:name=".MyAidlServletService"

android:enabled="true"

android:exported="true">

其中,"com.ting.android.aidldemo.UserInfo"是客户端要访问AIDL服务的ID。客户端要保持一致。

客户端的实现

将服务端的aidl文件包直接拷贝到客户端同样的目录下面。

d9e3b4d4361a

客户端aidl.png

新建一个ServiceConnection,在里面获取到UserInfo的对象

/**

* 需要绑定远程的Service

*/

private class MyServletConn implements ServiceConnection {

@Override

public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

userInfo = UserInfo.Stub.asInterface(iBinder);

Log.i("AIDL: ","绑定成功");

}

@Override

public void onServiceDisconnected(ComponentName componentName) {

userInfo = null;

}

}

通过intent绑定Service

Intent mIntent = new Intent("com.ting.android.aidldemo.UserInfo"); //服务器配置的 action name 要保持一致。

mIntent.setPackage("com.ting.android.aidldemo"); //这里设置服务器的包名,这样避免要求显示调用

bindService(mIntent, new MyServletConn(), BIND_AUTO_CREATE);

传递复杂数据的AIDL服务

AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据就需要做进一步处理,AIDL服务支持的数据类型如下:

Java的简单类型(int、char、boolean),不需要导入(import)

String和CharSequence。不需要导入(import)

List和Map。但是要注意,List和Map对象的元素类型必须是AIDL服务支持的数据类型。不需要导入(import)

AIDL自动生成的接口。需要导入(import)

实现android.os.Parcelable接口的类,需要导入(import)

对于传递需要导入的复杂数据类型,具体的操作步骤如下

服务端实现

创建一个IMyAidlInterface.aidl文件

// IMyAidlInterface.aidl

package com.ting.android.aidldemo;

//注意:这里有一个巨坑,这包名不能加aidl。不然会报错

import com.ting.android.aidldemo.Product;

interface IMyAidlInterface {

Map getMap(in String country, in Product product);

Product getProduct();

}

Product是一个实现android.os.Parcelable接口的类,需要使用import导入这个类。如果方法的类型是非简单类型,例如,String、List或者自定义的类,需要使用in、out或inout进行修饰,其中in表示这个值可以被客户端设置,out表示这个值可以被服务端设置,inout表示这个值既可以被客户端设置,又可以被服务端设置。

编写Product类,该类是用于传递的数据类型

public class Product implements Parcelable {

private int id;

private String name;

private float price;

public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {

@Override

public Product createFromParcel(Parcel parcel) {

return new Product(parcel);

}

@Override

public Product[] newArray(int i) {

return new Product[i];

}

};

public Product() {

}

Product(Parcel in) {

readFromParcel(in);

}

@Override

public int describeContents() {

return 0;

}

public void readFromParcel(Parcel parcel) {

id = parcel.readInt();

name = parcel.readString();

price = parcel.readFloat();

}

@Override

public void writeToParcel(Parcel parcel, int i) {

parcel.writeInt(id);

parcel.writeString(name);

parcel.writeFloat(price);

}

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public float getPrice() {

return price;

}

public void setPrice(float price) {

this.price = price;

}

@Override

public String toString() {

return "Product{" +

"id=" + id +

", name='" + name + '\'' +

", price=" + price +

'}';

}

}

Product类必须实现android.os.Parcelable接口,该接口用于序列化。在Product类中必须有一个静态常量,常量名必须是CREATOR,而且CREATOR常量的数据类型必须是Parcelable.Creator。通过实现newArray和createFromParcel方法可以将序列化的数据转换为Product对象和Product数组。在readFromParcel方法中需要从序列化数据读取相应的值。在writeToParcel方法中需要将要序列化数据写入Parcel对象。从这一点,对象序列化和反序列化的过程是通过手工完成的。

编写一个Product.aidl文件

package com.ting.android.aidldemo;

parcelable Product;

编写一个IMyAidlInterface类

// IMyAidlInterface.aidl

package com.ting.android.aidldemo;

//注意:这里有一个巨坑,这包名不能加aidl。不然会报错

import com.ting.android.aidldemo.Product;

interface IMyAidlInterface {

Map getMap(in String country, in Product product);

Product getProduct();

}

在Androidmainifest.xml文件中配置IMyAidlInterface

android:name=".MyService"

android:enabled="true"

android:exported="true">

客户端实现

将服务端的aidl文件包直接拷贝到客户端同样的目录下面。

d9e3b4d4361a

服务端aidl.png

新建一个ServiceConnection,在里面获取到UserInfo的对象

private class MyServiceConnection implements ServiceConnection {

@Override

public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);

Log.i("AIDL: ", "绑定成功");

}

@Override

public void onServiceDisconnected(ComponentName componentName) {

iMyAidlInterface = null;

}

}

通过intent绑定Service

Intent mIntent2 = new Intent("com.ting.android.aidldemo.MyService");

mIntent2.setPackage("com.ting.android.aidldemo"); //这里设置服务器的包名,这样避免要求显示调用

bindService(mIntent2, new MyServiceConnection(), BIND_AUTO_CREATE);

注意:

在开发过程中,对于复杂类型需要导入,容易出现找不到导入的包。需要在gradle.build中添加如下代码。

sourceSets {

main {

java.srcDirs = ['src/main/aidl']

}

}

sourceSets {

main {

manifest.srcFile 'src/main/AndroidManifest.xml'

java.srcDirs = ['src/main/java', 'src/main/aidl']

resources.srcDirs = ['src/main/java', 'src/main/aidl']

aidl.srcDirs = ['src/main/aidl']

res.srcDirs = ['src/main/res']

assets.srcDirs = ['src/main/assets']

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值