Android间的进程通讯(传递复杂对象)
完成对复杂对象的序列化
在Android中传递复杂数据类型的时候要通过将序列化,在Android中提供了一个接口Parcelable来实现对对象的序列化。
下面对需要传输的对象进行序列化操作,首先看自定义的类Person。
package com.example.service_parcelable_conmmute.bean; import android.graphics.Bitmap; /** * 用来传输的对象结构 * @author Xinyuyu * */ public class Person { private String name; private String age; private Bitmap figure; public Person(){ } public Person(String name, String age, Bitmap figure){ this.name = name; this.age = age; this.figure =figure; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public Bitmap getFigure() { return figure; } public void setFigure(Bitmap figure) { this.figure = figure; } }
这个类就是一般的JavaBean包含了一些get/set方法,我们要做的就是在进程之间传递该对象的值。所以就要将该对象进行序列化,下面实现一个类来完成该任务。
建立ParcelablePerson类,来完成对Person的序列化和反序列化的操作。其代码如下:
public class ParcelablePerson implements Parcelable { Person person = new Person(); public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public ParcelablePerson(Person person){ this.person = person; } public ParcelablePerson(Parcel source){ person.setName(source.readString()); person.setAge(source.readString()); person.setFigure((Bitmap)source.readParcelable(Bitmap.class.getClassLoader())); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(person.getName()); dest.writeString(person.getAge()); dest.writeParcelable(person.getFigure(), PARCELABLE_WRITE_RETURN_VALUE); } public static final Parcelable.Creator<ParcelablePerson> CREATOR = new Parcelable.Creator<ParcelablePerson>(){ @Override public ParcelablePerson createFromParcel(Parcel source) { return new ParcelablePerson(source); } @Override public ParcelablePerson[] newArray(int size) { return new ParcelablePerson[size]; } }; }
这段代码中完成了对Person对象的序列化与反序列化,实现Parcelable接口要做的就是来重写几个方法(分别完成序列化和反序列化),writeToParcel(Parcel dest, int flags)完成的就是对对象的序列化
其中的参数Parcel是一个容器,将对象放入其中就是序列化的过程。而CREATOR中的createFormParcel(Parcel source)来完成的就是反序列化,可以返回一个复杂的对象。实现了这写,就完成了对复杂对象的序列化和反序列化操作,这样我们就可以对它进行传输了。
完成绑定服务,完成进程中的通讯
以上我们只是完成了对一个复杂对象的序列化,下面我们要做的是建立服务,并且完成传输。
首先我们要做的是创建一个服务,在Android中创建一个服务要做的就是去实现Service接口。下面是发送对象的一个服务代码
public class ServiceForSendObject extends Service { private static final String MSG = "MESSAGE"; private ParcelablePerson parcelablePerson; private Person person; // ===================================== SendObject.Stub sendBinder = new Stub(){ @Override public ParcelablePerson getPersonInfo() throws RemoteException { Log.i(MSG, "调用getPersonInfo()接口实现,返回一个序列化的对象"); return parcelablePerson; }}; // ===================================== @Override public void onCreate() { person = new Person("xinyuyu", "25", BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.ic_launcher))); parcelablePerson = new ParcelablePerson(person); super.onCreate(); Log.i(MSG, "回调onCreate()创建服务"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(MSG, "回调onStartCommand()启动服务"); return super.onStartCommand(intent, flags, startId); } @Override public boolean onUnbind(Intent intent) { Log.i(MSG, "回调onUnbind解绑服务"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.i(MSG, "回调onDestroy销毁服务"); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { Log.i(MSG, "回调onBind()方法绑定服务"); return sendBinder; } }
在该段代码中输出各个阶段的一些信息,关键是在onCreat()方法中完成实例化一个对象,并且对该对象完成序列化操作。在分割线之间的代码是关键代码,注意在IBinder()中返回的是一个SendObject.Stub对象。而这个类是如何生成的呢?我们在完成进程间传输的时候需要用到Android中的AIDL语言来定义一个接口,下面我们来建立一个名为SendObject的aidl文件,SendObject.aidl
package com.example.service_parcelable_conmmute_service.aidl; import com.example.service_parcelable_conmmute.bean.ParcelablePerson; interface SendObject { ParcelablePerson getPersonInfo(); }
这个接口中的import会报错,这时候需要在建立一个AIDL文件,将其名字设置为和序列化类一样,这里就起做ParcelablePerson.aidl。其内容如下
package com.example.service_parcelable_conmmute.bean;
parcelable ParcelablePerson;
完成这些就不会有错误了。
这时候你会发现在gen目录下有一个和你的aidl名字一样Java文件即SendObject.java。而我们使用的SendObject.Stub就在其中。打开这个文件看一下,你会发现SendObject.Stub是这样一个类,实现了SendObject接口并且继承了android.os.Binder类。这样我们就重写SendObject方法,将其实现功能。就是分割线直接的代码。
public static abstract class Stub extends android.os.Binder implements com.example.service_parcelable_conmmute_service.aidl.SendObject
还要注意一点进程间的服务通讯应该更改AndroidManifest.xml文件的属性,如下
<service android:name="com.example.service_parcelable_conmmute.service.ServiceForSendObject"
android:process=":remote">
<intent-filter>
<action android:name="com.example.service_parcelable_conmmute.service.SEND_OBJECT"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
这样可以完成隐式的传递Intent。完成了这些,服务端就完成了。这个时候可以运行下代码。
启动界面
点击初始化服务后,可以看到服务开始运行
红色框中为我们的服务。
点击两按钮后LogCat输出的信息
从中可以看出来这个服务的生命周期。
以上我们就完成了服务端的工作了,下面来进行客户端的完成。
在客户端我们首先需要的是将服务端写好的那些AIDL文件和实体类拷贝到该工程下(连同包名进行拷贝)如下图
然后我们所要完成的就是完成客户端的activity程序了。将俩个程序进行联系的就是我们的SendObject接口。看下面代码
public class A extends Activity { private Button show_button; private TextView show_name_age; private ImageView show_image; private Button unbind_ser; private SendObject sendObject; private ParcelablePerson parcelablePerson; private Person person; private ServiceConnection connection = new ServiceConnection(){ // 建立绑定后service程序调用onBind()方法,返回一个IBinder对象 @Override public void onServiceConnected(ComponentName name, IBinder service) { sendObject = SendObject.Stub.asInterface(service); try { parcelablePerson = sendObject.getPersonInfo(); person = parcelablePerson.getPerson(); Log.i("", person.getName()); show_name_age.setText(person.getName() + "\n" + person.getAge()); show_image.setImageBitmap(person.getFigure()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.i("", "error"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a); show_button = (Button)this.findViewById(R.id.button1); show_name_age = (TextView)this.findViewById(R.id.textView1); show_image = (ImageView)this.findViewById(R.id.imageView1); unbind_ser = (Button)this.findViewById(R.id.button2); show_button.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // 隐式传递intent Intent intent = new Intent(); intent.setAction("com.example.service_parcelable_conmmute.service.SEND_OBJECT"); bindService(intent, connection, BIND_AUTO_CREATE); }}); // 解除绑定(服务会在activity销毁后自动销毁) unbind_ser.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { unbindService(connection); } }); } }
将该程序与服务进行绑定就用到了bindService()方法,看该方法中的参数,第一个是一个intent,第二个是一个ServiceConnection类,与服务建立连接,接收到onBind()传输的数据。从这个方法中我们就得到了传递过来的对象。运行客户端程序
点击第一个按钮后会显示出来一个Person对象的信息。这就说明数据从服务端传输了过来。
LogCat输出的信息