Android中Parcelable接口的应用

时间:2022-11-21 20:25:58

  在前面的一篇文章<基于Android应用开发的跨进程通信实现(IPC)>介绍了通过跨进程实现基本数值类型(String)的传递,但是有的时候,需要跨进程实现传递相对较复杂的数据(比如图片之类的资源),而不仅仅是基本数据。那么,如何实现复杂数据跨进程的传递使用呢?这时候就不得不把Parcelable接口搬出来了,假设我们需要跨进程的数据都包装在一个我们自定义的类里面,那么这个类就需要实现Parcelable这个接口了;

   下面就以一个Demo来说明如何通过实现Parcelable这个接口实现传递复杂数据;

  这个Demo的效果如下:       

   Android中Parcelable接口的应用

    实现效果:在编辑框中输入相应的姓名(这些姓名要对应服务端中保存的用户信息姓名),点击按钮,将会得到相应的用户信息(姓名、手机号、头像),这些用户信息都是来自与客户端不在同一个进程的服务端的;


   这个Demo包括两个应用程序:

    1. 服务端应用程序,它的文件组成结构如下:

   Android中Parcelable接口的应用

  2.客户端应用程序,它的文件组成结构如下:

 Android中Parcelable接口的应用

  通过上面的服务端和客户端应用程序的文件结构可知,它们都共同有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