Android间的进程通讯(传递复杂对象)

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输出的信息

时间: 2024-10-12 14:57:06

Android间的进程通讯(传递复杂对象)的相关文章

Android 开发笔记——通过 Intent 传递类对象

Android中Intent传递类对象提供了两种方式一种是 通过实现Serializable接口传递对象,一种是通过实现Parcelable接口传递对象. 要求被传递的对象必须实现上述2种接口中的一种才能通过Intent直接传递. Intent中传递这2种对象的方法: Bundle.putSerializable(Key,Object); //实现Serializable接口的对象 Bundle.putParcelable(Key, Object); //实现Parcelable接口的对象 以下

android利用apkplug框架实现主应用与插件通讯(传递随意对象)实现UI替换

时光匆匆,乍一看已半年过去了,经过这半年的埋头苦干今天最终有满血复活了. 利用apkplug框架实现动态替换宿主Activity中的UI元素.以达到不用更新应用就能够更换UI样式的目的. 先看效果图: 首先理解OSGI服务的基本概念,例如以下图 1.首先定义一个java接口(interface)用于规范宿主与插件之间的通讯协议 interface  com.apkplug.osgi.service.showView void showView(Bundle bundle,View v,int i

Android中跨进程通信传递Parcelable对象时出现android.os.BadParcelableException: ClassNotFoundException when unmarsh

转载请注明出处:http://blog.csdn.net/bettarwang/article/details/45315091 按Google开发文档的说法,在跨进程通信时,推荐使用MessengerService而不是AIDL,所以最近在实现一个跨进程的Service时就采用了MessengerService的方法. 然后定义了这样一个类: public class BleServiceBean implements Parcelable { private String name; pri

android利用apkplug框架实现主应用与插件通讯(传递任意对象)实现UI替换

时光匆匆,乍一看已半年过去了,经过这半年的埋头苦干今天终于有满血复活了. 利用apkplug框架实现动态替换宿主Activity中的UI元素,以达到不用更新应用就可以更换UI样式的目的. 先看效果图: 首先理解OSGI服务的基本概念,如下图 1.首先定义一个java接口(interface)用于规范宿主与插件之间的通讯协议 interface  com.apkplug.osgi.service.showView void showView(Bundle bundle,View v,int ind

android 史上最简单易懂的跨进程通讯(Messenger)!

不需要AIDL也不需要复杂的ContentProvider,也不需要SharedPreferences或者共享存储文件! 只需要简单易懂的Messenger,它也称为信使,通过它可以在不同进程中传递message对象,在message中放入我们需要传递的数据你就可以实现跨进程通讯和传递数据.废话不多说,直接上代码. 首先是服务端: public class Ser extends Service{ @Override public IBinder onBind(Intent intent) {

Android 之 IPC 进程通信全解析

Android 之 IPC 进程通信全解析 本篇博客的框架 什么是IPC IPC(Inter-Process Communication) 进程间通信,是指两个不同进程之间数据交换的过程. 在明确其之前,需要先搞懂几个概念: 线程:CPU可调度的最小单位,是程序执行流的最小单元:线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源. 进程: 一个执行单元,在PC 和移动设备上一

【转】android中跨进程通讯的4种方式

转自:http://www.androidsdn.com/article/show/137 由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于android系统中4种应用程序组件:Activity.Content Provider.Broadcast和Service. 其中Activity可以跨进程调用其他应用程序的Activity: Content Pro

一个进程间同步和通讯的 C# 框架

转自原文 一个进程间同步和通讯的 C# 框架 threadmsg_demo.zip ~ 41KB    下载 threadmsg_src.zip ~ 65KB    下载 0.背景简介 微软在 .NET 框架中提供了多种实用的线程同步手段,其中包括 monitor 类及 reader-writer锁.但跨进程的同步方法还是非常欠缺.另外,目前也没有方便的线程间及进程间传递消息的方法.例如C/S和SOA,又或者生产者/消费者模式中就常常需要传递消息.为此我编写了一个独立完整的框架,实现了跨线程和跨

Android剪切板传递数据传递序列化对象数据

一.剪切板的使用介绍 1. 剪切板对象的创建 使用剪切板会用到,ClipboardManager对象,这个对像的创建不可以使用构造方法,主要是由于没有提供public的构造函数(单例模式),需要使用Activity.getSystemService(Context.CLIPBOARD_SERVICE)获取该对象.  2. 对象调用的主要方法介绍 在Android-11(Android 3.0)版本之前,利用剪切板传递数据使用setText()和getText()方法,但是在此版本之后,这两个方法