在前面的一篇文章<基于Android应用开发的跨进程通信实现(IPC)>介绍了通过跨进程实现基本数值类型(String)的传递,但是有的时候,需要跨进程实现传递相对较复杂的数据(比如图片之类的资源),而不仅仅是基本数据。那么,如何实现复杂数据跨进程的传递使用呢?这时候就不得不把Parcelable接口搬出来了,假设我们需要跨进程的数据都包装在一个我们自定义的类里面,那么这个类就需要实现Parcelable这个接口了;
下面就以一个Demo来说明如何通过实现Parcelable这个接口实现传递复杂数据;
这个Demo的效果如下:
实现效果:在编辑框中输入相应的姓名(这些姓名要对应服务端中保存的用户信息姓名),点击按钮,将会得到相应的用户信息(姓名、手机号、头像),这些用户信息都是来自与客户端不在同一个进程的服务端的;
这个Demo包括两个应用程序:
1. 服务端应用程序,它的文件组成结构如下:
2.客户端应用程序,它的文件组成结构如下:
通过上面的服务端和客户端应用程序的文件结构可知,它们都共同有Person.java、IMyService.aidl、Person.aidl等文件;
当然通过之前的<基于Android应用开发的跨进程通信实现(IPC)>的介绍可知,要想实现两个应用程序之间跨进程调用,两个应用程序必须共同拥有aidl文件。
下面将介绍这些文件的实现:
1. Person.java:
Person类相当于一个包装用户信息数据的javaBean,该类实现Parcelable接口,是实现跨进程传递复杂数据的自定义类,代码实现如下:
package com.feixun.hu.ipc.service;
import java.util.Map;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable
{
/*picture集合保存的是头像的Bitmap
* 注:此处不能是Drawable,Parcel是不能跨进程传递Drawable类型的,Bitmap类型是可以的
*/
private Map<String, Bitmap> picture;
private String name;
private String phone;
public Person(String name, String phone, Map<String, Bitmap> picture)
{
this.name = name;
this.phone = phone;
this.picture = picture;
}
public Map<String, Bitmap> getPictures() {
return picture;
}
public void setPictures(Map<String, Bitmap> picture) {
this.picture = picture;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public int describeContents()
{
// TODO Auto-generated method stub
return 0;
}
//实现Parcel接口必须覆盖实现的方法
@Override
public void writeToParcel(Parcel dest, int flags)
{
// TODO Auto-generated method stub
/*将Person的成员写入Parcel,
* 注:Parcel中的数据是按顺序写入和读取的,即先被写入的就会先被读取出来
*/
dest.writeString(name);
dest.writeString(phone);
dest.writeMap(picture);
}
//该静态域是必须要有的,而且名字必须是CREATOR,否则会出错
public static final Parcelable.Creator<Person> CREATOR =
new Parcelable.Creator<Person>()
{
@Override
public Person createFromParcel(Parcel source)
{
// TODO Auto-generated method stub
//从Parcel读取通过writeToParcel方法写入的Person的相关成员信息
String name = source.readString();
String phone = source.readString();
Map<String, Bitmap> picture = source.readHashMap(new ClassLoader()
{
});
//更加读取到的信息,创建返回Person对象
return new Person(name, phone, picture);
}
@Override
public Person[] newArray(int size)
{
// TODO Auto-generated method stub
//返回Person对象数组
return new Person[size];
}
};
}
2. Person.aidl:
Person作为实现跨进程传递复杂数据的类必须要创建一个对应的aidl文件对其进行声明,内容如下:
parcelable Person;
3. IMyService.aidl:
该文件和之前的<基于Android应用开发的跨进程通信实现(IPC)>文章中介绍的IMyService.aidl文件的作用一样,是实现跨进程的重要文件实现,内容如下:
package com.feixun.hu.ipc.service;
import com.feixun.hu.ipc.service.Person;
interface IMyService
{
Person getPerson(String name);
}
IMyService.aidl文件会在应用程序的gen目录中生成对应的IMyService.java文件;
以上这些文件时服务端和客户端必须共同拥有的,服务端实现将用户数据信息保存在客户端的Person对象,而客户端通过跨进程通信(IPC)获取得到服务端保存的那些用户信息数据,然后通过ListView不断添加显示出来;
服务端应用程序的代码实现如下:
IpcService.java
package com.feixun.hu.ipc.service;
import java.util.HashMap;
import java.util.Map;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.IBinder;
import android.os.RemoteException;
public class IpcService extends Service
{
//创建一个用于保存Person对象信息的HashMap对象
private Map<String, Person> mPersons = new HashMap<String, Person>();
//创建一个用于保存头像图片的HashMap对象
private Map<String, Bitmap> mPictures = new HashMap<String, Bitmap>(); ;
private ServiceBinder mServiceBinder;
private String[] names;
private String[] phones;
private Bitmap[] pictures;
/*初始化用户的姓名、手机号、头像(注:当我们在客户端要检索这些用户信息时,
* 输入的用户名必须是names数组中的任意一个)
*/
private void init()
{
names = new String[]{"steven", "lisa", "rose", "sara", "masa",
"james", "wade", "bosh", "hamslan", "bati"};
phones = new String[]{"15898930099", "13909456674", "13465353623",
"15984347533", "18694335633", "18945660044", "13844423094", "15899335395", "18754636894", "13986745568"};
pictures = new Bitmap[]{getPicture(R.drawable.image1), getPicture(R.drawable.image2),
getPicture(R.drawable.image3), getPicture(R.drawable.image4),
getPicture(R.drawable.image5), getPicture(R.drawable.image6),
getPicture(R.drawable.image7), getPicture(R.drawable.image8),
getPicture(R.drawable.image9), getPicture(R.drawable.image10)};
for (int i = 0; i < names.length; i++)
{
mPictures.put(names[i], pictures[i]);
mPersons.put(names[i] , new Person(names[i], phones[i], mPictures));
}
}
//将Drawable转为Bitmap
private Bitmap getPicture(int resourceId)
{
BitmapDrawable bd = (BitmapDrawable)getResources().getDrawable(resourceId);
return bd.getBitmap();
}
@Override
public void onCreate()
{
// TODO Auto-generated method stub
super.onCreate();
init();
//person = new Person();
//创建ServiceBinder对象(Binder类型对象)
mServiceBinder = new ServiceBinder();
}
/*定义一个继承IMyService接口内部类Stub的实现与客户端通信的Binder类型的类,
* IMyService.Stub是Binder类型
*/
public class ServiceBinder extends IMyService.Stub
{
@Override
public Person getPerson(String name) throws RemoteException
{
// TODO Auto-generated method stub
//根据传进来的用户姓名,返回对应的Person对象
return mPersons.get(name);
}
}
@Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
/*与客户端连接时,返回该Binder对象.
* 1.如果连接的客户端和该服务端属于同一个进程,则此处直接返回mServiceBinder本身
* 2.如果连接的客户端和该服务不属于同一个进程,则返回的是mServiceBinder对象的代理
*/
return mServiceBinder;
}
}
IpcClient.java
package com.feixun.hu.ipc.client;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.feixun.hu.ipc.service.IMyService;
import com.feixun.hu.ipc.service.Person;
public class IpcClient extends Activity
{
private IMyService mIMyService;
private ContactAdapter mContactAdapter;
private Person mPerson;
private Button mGetInfo;
private ListView showView;
private EditText mInputName;
private List<Person> mPersons;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//获取各组件
mGetInfo = (Button) findViewById(R.id.get);
mInputName = (EditText) findViewById(R.id.person);
showView = (ListView)findViewById(R.id.show);
//创建mPersons集合对象
mPersons = new ArrayList<Person>();
//创建Intent,对应服务端注册的Intent
Intent intent = new Intent();
intent.setAction("com.feixun.hu.action.IPC_SERVICE");
//绑定连接远程服务
bindService(intent, conn, Service.BIND_AUTO_CREATE);
//为设置按钮绑定监听
mGetInfo.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
if(mInputName.getText() != null )
{
try
{
String personName = mInputName.getText().toString();
//得到来自远程的Person对象mPerson
mPerson = mIMyService.getPerson(personName);
if (mPerson != null)
{
getInfo(mPerson);
}
}
catch (RemoteException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
//该方法实现在ListView显示从远程得到的相关信息
private void getInfo(Person person)
{
//将从远程得到的mPerson对象添加入mPersons集合
mPersons.add(person);
//通过远程得到的mPerson对象
mContactAdapter = new ContactAdapter(this, mPersons);
showView.setAdapter(mContactAdapter);
}
//实现客户端与服务端绑定的关键部分
private ServiceConnection conn = new ServiceConnection()
{
//解除连接服务端
@Override
public void onServiceDisconnected(ComponentName name)
{
// TODO Auto-generated method stub
mIMyService = null;
}
//连接服务端
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
// TODO Auto-generated method stub
/*此处实现获取通过IpcService的onBind方法返回的mServiceBinder对象的代理。
* 参数service为绑定获得的远程服务IpcService的mServiceBinder对象,
* 而调用IMyService.Stub的函数asInterface获取的是mServiceBinder对象的代理。
*/
mIMyService = IMyService.Stub.asInterface(service);
}
};
@Override
protected void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
//解除绑定
unbindService(conn);
}
//自定义适配器,然后将从远程得到的用户信息在ListView中显示
class ContactAdapter extends BaseAdapter
{
private List<Person> persons = null;
private LayoutInflater inflater = null;
public ContactAdapter(Context context, List<Person> person)
{
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
persons = person;
//Log.d("MainActivity", "FxAdapter()");
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return persons.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return persons.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
// TODO Auto-generated method stub
//得到来自远程服务端的Person对象
Person person = (Person)persons.get(position);
ImageView mPictureView = null;
TextView mNameView = null;
TextView mPhoneView = null;
if (convertView == null)
{
convertView = inflater.inflate(R.layout.contact_list, null);
}
mPictureView = (ImageView)convertView.findViewById(R.id.user_image);
//显示头像
mPictureView.setImageBitmap(person.getPictures().get(person.getName()));
mNameView = (TextView)convertView.findViewById(R.id.name_id);
//显示姓名
mNameView.setText(person.getName());
mPhoneView = (TextView)convertView.findViewById(R.id.phone_id);
//显示手机号
mPhoneView.setText(person.getPhone());
return convertView;
}
}
}
关于通过实现Parcelable接口来进行程跨进程传递复杂数据的实现就到此结束了,相关代码下载链接地址如下: