实际开发中,我们可能需要考虑传递复杂数据类型的情况!下面我们来学习下 如何向服务端传递复杂数据类型的数据!开始之前我们先来了解Parcelable接口!
Parcelable接口简介:
相信用过序列化的基本上都知道这个接口了,除了他还有另外一个Serializable,同样是用于序列化的, 只是Parcelable更加轻量级,速度更快!但是写起来就有点麻烦了,当然如果你用的as的话可以用 的插件来完成序列化,比如:Android Parcelable Code Generator 当然,这里我们还是手把手教大家来实现这个接口~
首先需要实现:writeToParcel和readFromPacel方法 写入方法将对象写入到包裹(parcel)中,而读取方法则从包裹中读取对象, 请注意,写入属性顺序需与读取顺序相同。
接着需要在:该类中添加一个名为CREATOR的static final属性 改属性需要实现:android.os.Parcelable.Creator接口。
再接着需要从写接口中的两个方法: createFromParcel(Parcel source)方法:实现从source创建出JavaBean实例的功能 newArray(int size):创建一个类型为T,长度为size的数组,只有一个简单的return new T[size]; (这里的T是Person类)。
最后,describeContents():这个我也不知道是拿来干嘛的,直接返回0即可!不用理他。
另外,非原始类型中,除了String和CharSequence以外,其余均需要一个方向指示符。 方向指示符包括 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下自定义类型有点问题