在前面的一篇文章<基于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接口来进行程跨进程传递复杂数据的实现就到此结束了,相关代码下载链接地址如下: