原文链接:http://blog.csdn.net/stevenhu_223/article/details/9209575
在前面的一篇文章<基于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接口来进行程跨进程传递复杂数据的实现就到此结束了,相关代码下载链接地址如下:
http://download.csdn.net/detail/stevenhu_223/5676401