只会幻想而不行动的人,永远也体会不到收获果实时的喜悦。
本讲内容:Android之进程间传递自定义类型参数
上一讲我们讲解了简单的AIDL进程间通信的操作,客户端向服务端发送一个String类型的参数,服务端也返回一个String类型的结果,本讲我们讲解向服务端传递复杂的数据类型。
一、AIDL对Java类型的支持:
AIDL默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),如果要传递自定义的类型该如何实现呢?
二、传递自定义的类型:
要传递自定义类型,首先要让自定义类型支持parcelable协议,实现步骤如下:
第一步:自定义类型必须实现Parcelable接口,并且实现Parcelable接口的public void writeToParcel(Parcel dest, int flags)方法 。
第二步:自定义类型中必须含有一个名称为CREATOR的静态成员,该成员对象要求实现Parcelable.Creator接口及其方法。
第三步:创建一个aidl文件声明你的自定义类型。
三、Parcelable接口的作用:
实现了Parcelable接口的实例可以将自身的状态信息(状态信息通常指的是各成员变量的值)写入Parcel,也可以从Parcel中恢复其状态。 Parcel用来完成数据的序列化传递。
四、下面我们通过一个例子讲解:
客户端和服务端的源码结构如下:
(一)建立一个服务端的工程的步骤:
第一步:创建自定义类型,并实现Parcelable接口,使其支持parcelable协议。如:在com.person.aidl创建Person.java:
package com.person.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
private String name;
private int sex;
// 必须提供一个名为CREATOR的static final属性 该属性需要实现android.os.Parcelable.Creator<T>接口
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
return new Person(source);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
public Person() {
}
private Person(Parcel source) {
readFromParcel(source);
}
@Override
public int describeContents() {
return 0;
}
// 注意写入变量和读取变量的顺序应该一致 不然得不到正确的结果
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(sex);
}
// 注意读取变量和写入变量的顺序应该一致 不然得不到正确的结果
public void readFromParcel(Parcel source) {
name = source.readString();
sex = source.readInt();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
}
package com.person.aidl;
parcelable Person;
第三步: 在接口aidl文件中使用自定义类型,需要使用import显式导入,创建IGreetService.aidl文件,代码如下:
package com.person.aidl;
import com.person.aidl.Person;
interface IGreetService {
String greet(in Person person);
}
第四步: 建立一个服务类(Service的子类)代码如下:
public class AIDLService extends Service {
private static final String TAG = "MyService";
IGreetService.Stub stub = new IGreetService.Stub() {
@Override
public String greet(Person person) throws RemoteException {
Log.i(TAG, "greet(Person person) called");
String greeting = "hello, " + person.getName();
switch (person.getSex()) {
case 0:
greeting = greeting + ", you're handsome.";
break;
case 1:
greeting = greeting + ", you're beautiful.";
break;
}
return greeting;
}
};
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind() called");
return stub;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind() called");
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy() called");
}
}
在AndroidManifest.xml中配置
<service android:name=".AIDLService" >
<intent-filter>
<action android:name="android.intent.action.AIDLService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
(二)建立一个客户端的工程的步骤:
第一步:把com.person.aidl包的文件拷到相应的目录中和服务端一样,使服务端和客户端在通信协议上达到了统一。
第二步:主要工作在MainActivity中完成。代码如下:
public class MainActivity extends Activity implements OnClickListener {
private static final String TAG = "MyService";
private Button bindBtn;
private Button greetBtn;
private Button unbindBtn;
private IGreetService greetService;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected() called");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected() called");
greetService = IGreetService.Stub.asInterface(service);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindBtn = (Button) findViewById(R.id.bindService);
greetBtn = (Button) findViewById(R.id.greet);
unbindBtn = (Button) findViewById(R.id.unbindService);
bindBtn.setOnClickListener(this);
greetBtn.setOnClickListener(this);
unbindBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bindService:
Intent intent = new Intent("android.intent.action.AIDLService");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
bindBtn.setEnabled(false);
greetBtn.setEnabled(true);
unbindBtn.setEnabled(true);
break;
case R.id.greet:
try {
Person person = new Person();
person.setName("dan");
person.setSex(0);
String retVal = greetService.greet(person);
Toast.makeText(MainActivity.this, retVal, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
Toast.makeText(MainActivity.this, "error", Toast.LENGTH_SHORT).show();
}
break;
case R.id.unbindService:
unbindService(conn);
bindBtn.setEnabled(true);
greetBtn.setEnabled(false);
unbindBtn.setEnabled(false);
break;
}
}
}
下面是运行结果:(要先启动服务器)
点击bindService
点击greet
点击unbindService
本讲就到这里,Take your time and enjoy it