Android问题—传递复杂数据的AIDL Service

本文介绍了如何在Android中通过AIDL传递复杂数据类型,如Person和Salary对象,涉及到Parcelable接口的实现,包括writeToParcel、readFromParcel方法以及CREATOR属性。在服务端创建AIDL文件,定义接口和方法,客户端拷贝AIDL文件并绑定服务,通过ServiceConnection获取并显示数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实际开发中,我们可能需要考虑传递复杂数据类型的情况!下面我们来学习下 如何向服务端传递复杂数据类型的数据!开始之前我们先来了解Parcelable接口

Parcelable接口简介:

相信用过序列化的基本上都知道这个接口了,除了他还有另外一个Serializable,同样是用于序列化的, 只是Parcelable更加轻量级,速度更快!但是写起来就有点麻烦了,当然如果你用的as的话可以用 的插件来完成序列化,比如:Android Parcelable Code Generator 当然,这里我们还是手把手教大家来实现这个接口~

首先需要实现:writeToParcelreadFromPacel方法 写入方法将对象写入到包裹(parcel)中,而读取方法则从包裹中读取对象, 请注意,写入属性顺序需与读取顺序相同。

接着需要在:该类中添加一个名为CREATORstatic final属性 改属性需要实现:android.os.Parcelable.Creator接口

再接着需要从写接口中的两个方法: createFromParcel(Parcel source)方法:实现从source创建出JavaBean实例的功能 newArray(int size):创建一个类型为T,长度为size的数组,只有一个简单的return new T[size]; (这里的T是Person类)。

最后describeContents():这个我也不知道是拿来干嘛的,直接返回0即可!不用理他。

另外,非原始类型中,除了StringCharSequence以外,其余均需要一个方向指示符。 方向指示符包括 in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值。

好的,接着来写代码试试(AS这里自定义类型有点问题,暂时还没解决,就用回Eclipse~):

代码示例:
自定义两种对象类型:Person与Salary,Person作为调用远程的Service的参数,Salary作为返回值! 那么首先要做的就是创建Person与Salary类,同时需要实现Parcelable接口

1.服务端

Step 1:创建Person.aidl和Salary.aidl的文件,因为他们需要实现Parcelable接口,所以就下面一条语句

Person.aidl:     parcelable Person; 
Salary.aidl:     parcelable Salary; 

Step 2:分别建立Person类与Salary类,需实现Parcelable接口,重写对应的方法!

PS:因为我们后面是根据Person对象来获取Map集合中的数据,所以Person.java中我们重写了hashcode和equals 的方法;而Salary类则不需要!

Person.java:

package com.jay.example.aidl;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Jay on 2015/8/18 0018.
 */
public class Person implements Parcelable {

    private Integer id;
    private String name;

    public Person() {
    }

    public Person(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    // 实现Parcelable必须实现的方法,不知道拿来干嘛的,直接返回0就行了
    @Override
    public int describeContents() {
        return 0;
    }

    // 写入数据到Parcel中的方法
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        // 把对象所包含的数据写入到parcel中
        dest.writeInt(id);
        dest.writeString(name);
    }

    // 必须提供一个名为CREATOR的static final属性 该属性需要实现
    // android.os.Parcelable.Creator<T>接口
    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
        // 从Parcel中读取数据,返回Person对象
        @Override
        public Person createFromParcel(Parcel source) {
            return new Person(source.readInt(), source.readString());
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    // 因为我们集合取出元素的时候是根据Person对象来取得,所以比较麻烦,
    // 需要我们重写hashCode()和equals()方法
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

Salary.java

package com.jay.example.aidl;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Jay on 2015/8/18 0018.
 */
public class Salary implements Parcelable {

    private String type;
    private Integer salary;

    public Salary() {
    }

    public Salary(String type, Integer salary) {
        this.type = type;
        this.salary = salary;
    }

    public String getType() {
        return type;
    }

    public Integer getSalary() {
        return salary;
    }

    public void setType(String type) {
        this.type = type;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(type);
        dest.writeInt(salary);
    }

    public static final Parcelable.Creator<Salary> CREATOR = new Parcelable.Creator<Salary>() {
        // 从Parcel中读取数据,返回Person对象
        @Override
        public Salary createFromParcel(Parcel source) {
            return new Salary(source.readString(), source.readInt());
        }

        @Override
        public Salary[] newArray(int size) {
            return new Salary[size];
        }
    };

    public String toString() {
        return "工作:" + type + "    薪水: " + salary;
    }
}

Step 3:创建一个ISalary.aidl的文件,在里面写一个简单的获取工资信息的方法

package com.jay.example.aidl;

import com.jay.example.aidl.Salary;
import com.jay.example.aidl.Person;

interface ISalary {
    // 定义一个Person对象作为传入参数
    // 接口中定义方法时,需要制定新参的传递模式,这里是传入,所以前面有一个in
    Salary getMsg(in Person owner);
}

ps:这里可以记得如果使用的是自定义的数据类型的话,需要import哦!!!切记!!!

Step 4:核心Service的编写: 定义一个SalaryBinder类继承Stub,从而实现ISalary和IBinder接口;定义一个存储信息的Map集合! 重新onBind方法,返回SalaryBinder类的对象实例!

AidlService.java

package com.jay.example.aidl_complexservice;

import java.util.HashMap;
import java.util.Map;
import com.jay.example.aidl.ISalary.Stub;
import com.jay.example.aidl.Person;
import com.jay.example.aidl.Salary;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class AidlService extends Service {

    private SalaryBinder salaryBinder;
    private static Map<Person, Salary> ss = new HashMap<Person, Salary>();
    // 初始化Map集合,这里在静态代码块中进行初始化,当然你可也以在构造方法中完成初始化
    static {
        ss.put(new Person(1, "Jay"), new Salary("码农", 2000));
        ss.put(new Person(2, "GEM"), new Salary("歌手", 20000));
        ss.put(new Person(3, "XM"), new Salary("学生", 20));
        ss.put(new Person(4, "MrWang"), new Salary("老师", 2000));
    }

    @Override
    public void onCreate() {
        super.onCreate();
        salaryBinder = new SalaryBinder();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return salaryBinder;
    }

    // 同样是继承Stub,即同时实现ISalary接口和IBinder接口
    public class SalaryBinder extends Stub {
        @Override
        public Salary getMsg(Person owner) throws RemoteException {
            return ss.get(owner);
        }
    }

    @Override
    public void onDestroy() {
        System.out.println("服务结束!");
        super.onDestroy();
    }
}

注册下Service:

<service android:name=".AidlService">  
    <intent-filter>    
        <action android:name="android.intent.action.AIDLService" />  
        <category android:name="android.intent.category.DEFAULT" />  
    </intent-filter>    
</service>

2.客户端编写

Step 1:把服务端的AIDL文件拷贝下

Step 2:编写简单的布局,再接着就是核心MainActvitiy的实现了 定义一个ServciceConnection对象,重写对应方法,和前面的普通数据的类似 再接着在bindService,然后再Button的点击事件中获取Salary对象并显示出来!

MainActivity.java

package com.jay.example.aidl_complexclient;

import com.jay.example.aidl.ISalary;
import com.jay.example.aidl.Person;
import com.jay.example.aidl.Salary;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

    private ISalary salaryService;
    private Button btnquery;
    private EditText editname;
    private TextView textshow;
    private ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            salaryService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 返回的是代理对象,要调用这个方法哦!
            salaryService = ISalary.Stub.asInterface(service);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnquery = (Button) findViewById(R.id.btnquery);
        editname = (EditText) findViewById(R.id.editname);
        textshow = (TextView) findViewById(R.id.textshow);

        Intent it = new Intent();
        it.setAction("com.jay.aidl.AIDL_SERVICE");
        bindService(it, conn, Service.BIND_AUTO_CREATE);

        btnquery.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    String name = editname.getText().toString();
                    Salary salary = salaryService.getMsg(new Person(1, name));
                    textshow.setText(name + salary.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.unbindService(conn);
    }

}

PS: 这里的代码是之前用Eclipse写的代码,Android Studio下自定义类型有点问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值