Android中Parcelable接口的应用

来源:互联网 发布:js带复选框的下拉列表 编辑:程序博客网 时间:2024/05/17 07:09

 在前面的一篇文章<基于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接口,是实现跨进程传递复杂数据的自定义类,代码实现如下:

[java] view plain copy
  1. package com.feixun.hu.ipc.service;  
  2.   
  3. import java.util.Map;  
  4.   
  5. import android.graphics.Bitmap;  
  6. import android.graphics.drawable.Drawable;  
  7. import android.os.Parcel;  
  8. import android.os.Parcelable;  
  9.   
  10. public class Person implements Parcelable  
  11. {  
  12.   
  13.     /*picture集合保存的是头像的Bitmap 
  14.      * 注:此处不能是Drawable,Parcel是不能跨进程传递Drawable类型的,Bitmap类型是可以的 
  15.      */  
  16.     private Map<String, Bitmap> picture;  
  17.       
  18.     private String name;  
  19.     private String phone;  
  20.       
  21.     public Person(String name, String phone, Map<String, Bitmap> picture)  
  22.     {  
  23.         this.name = name;  
  24.         this.phone = phone;  
  25.         this.picture = picture;  
  26.     }  
  27.   
  28.     public Map<String, Bitmap> getPictures() {  
  29.         return picture;  
  30.     }  
  31.   
  32.     public void setPictures(Map<String, Bitmap> picture) {  
  33.         this.picture = picture;  
  34.     }  
  35.   
  36.     public String getName() {  
  37.         return name;  
  38.     }  
  39.   
  40.     public void setName(String name) {  
  41.         this.name = name;  
  42.     }  
  43.   
  44.     public String getPhone() {  
  45.         return phone;  
  46.     }  
  47.   
  48.     public void setPhone(String phone) {  
  49.         this.phone = phone;  
  50.     }  
  51.   
  52.     @Override  
  53.     public int describeContents()   
  54.     {  
  55.         // TODO Auto-generated method stub  
  56.         return 0;  
  57.     }  
  58.   
  59.     //实现Parcel接口必须覆盖实现的方法  
  60.     @Override  
  61.     public void writeToParcel(Parcel dest, int flags)   
  62.     {  
  63.         // TODO Auto-generated method stub  
  64.         /*将Person的成员写入Parcel, 
  65.          * 注:Parcel中的数据是按顺序写入和读取的,即先被写入的就会先被读取出来 
  66.          */  
  67.         dest.writeString(name);  
  68.         dest.writeString(phone);  
  69.         dest.writeMap(picture);  
  70.     }  
  71.   
  72.     //该静态域是必须要有的,而且名字必须是CREATOR,否则会出错  
  73.     public static final Parcelable.Creator<Person> CREATOR =  
  74.         new Parcelable.Creator<Person>()  
  75.     {  
  76.   
  77.         @Override  
  78.         public Person createFromParcel(Parcel source)   
  79.         {  
  80.             // TODO Auto-generated method stub  
  81.             //从Parcel读取通过writeToParcel方法写入的Person的相关成员信息  
  82.               
  83.             String name = source.readString();   
  84.             String phone = source.readString();  
  85.             Map<String, Bitmap> picture = source.readHashMap(new ClassLoader()   
  86.             {  
  87.             });  
  88.               
  89.             //更加读取到的信息,创建返回Person对象  
  90.             return new Person(name, phone, picture);  
  91.         }  
  92.   
  93.         @Override  
  94.         public Person[] newArray(int size)   
  95.         {  
  96.             // TODO Auto-generated method stub  
  97.             //返回Person对象数组  
  98.             return new Person[size];  
  99.         }  
  100.     };  
  101. }  

   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

[java] view plain copy
  1. package com.feixun.hu.ipc.service;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import android.app.Service;  
  7. import android.content.Intent;  
  8. import android.graphics.Bitmap;  
  9. import android.graphics.drawable.BitmapDrawable;  
  10. import android.os.IBinder;  
  11. import android.os.RemoteException;  
  12. public class IpcService extends Service   
  13. {  
  14.     //创建一个用于保存Person对象信息的HashMap对象  
  15.     private Map<String, Person>  mPersons = new HashMap<String, Person>();  
  16.     //创建一个用于保存头像图片的HashMap对象  
  17.     private Map<String, Bitmap> mPictures = new HashMap<String, Bitmap>(); ;  
  18.       
  19.     private ServiceBinder mServiceBinder;  
  20.       
  21.     private String[] names;  
  22.     private String[] phones;  
  23.     private Bitmap[] pictures;  
  24.   
  25.     /*初始化用户的姓名、手机号、头像(注:当我们在客户端要检索这些用户信息时, 
  26.      * 输入的用户名必须是names数组中的任意一个) 
  27.      */  
  28.     private void init()  
  29.     {  
  30.         names = new String[]{"steven""lisa""rose""sara""masa",   
  31.                 "james""wade""bosh""hamslan""bati"};  
  32.         phones = new String[]{"15898930099""13909456674""13465353623",   
  33.                 "15984347533""18694335633""18945660044""13844423094""15899335395""18754636894""13986745568"};  
  34.         pictures = new Bitmap[]{getPicture(R.drawable.image1), getPicture(R.drawable.image2),  
  35.                     getPicture(R.drawable.image3), getPicture(R.drawable.image4),  
  36.                     getPicture(R.drawable.image5), getPicture(R.drawable.image6),   
  37.                     getPicture(R.drawable.image7), getPicture(R.drawable.image8),  
  38.                     getPicture(R.drawable.image9), getPicture(R.drawable.image10)};  
  39.           
  40.          for (int i = 0; i < names.length; i++)  
  41.          {  
  42.              mPictures.put(names[i], pictures[i]);  
  43.              mPersons.put(names[i] , new Person(names[i], phones[i], mPictures));  
  44.          }  
  45.            
  46.     }  
  47.       
  48.     //将Drawable转为Bitmap  
  49.     private Bitmap getPicture(int resourceId)  
  50.     {  
  51.         BitmapDrawable bd = (BitmapDrawable)getResources().getDrawable(resourceId);  
  52.           
  53.         return bd.getBitmap();  
  54.           
  55.     }  
  56.       
  57.     @Override  
  58.     public void onCreate()   
  59.     {  
  60.         // TODO Auto-generated method stub  
  61.         super.onCreate();  
  62.         init();  
  63.         //person = new Person();  
  64.         //创建ServiceBinder对象(Binder类型对象)  
  65.         mServiceBinder = new ServiceBinder();  
  66.     }  
  67.   
  68.     /*定义一个继承IMyService接口内部类Stub的实现与客户端通信的Binder类型的类, 
  69.      * IMyService.Stub是Binder类型 
  70.      */  
  71.     public class ServiceBinder extends IMyService.Stub  
  72.     {  
  73.   
  74.         @Override  
  75.         public Person getPerson(String name) throws RemoteException   
  76.         {  
  77.             // TODO Auto-generated method stub  
  78.             //根据传进来的用户姓名,返回对应的Person对象  
  79.             return mPersons.get(name);  
  80.         }  
  81.     }  
  82.       
  83.     @Override  
  84.     public IBinder onBind(Intent arg0)   
  85.     {  
  86.         // TODO Auto-generated method stub  
  87.           
  88.         /*与客户端连接时,返回该Binder对象. 
  89.          * 1.如果连接的客户端和该服务端属于同一个进程,则此处直接返回mServiceBinder本身 
  90.          * 2.如果连接的客户端和该服务不属于同一个进程,则返回的是mServiceBinder对象的代理 
  91.          */  
  92.         return mServiceBinder;  
  93.     }  
  94. }  


    客户端的代码实现如下: 

    IpcClient.java

[java] view plain copy
  1. package com.feixun.hu.ipc.client;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.app.Service;  
  8. import android.content.ComponentName;  
  9. import android.content.Context;  
  10. import android.content.Intent;  
  11. import android.content.ServiceConnection;  
  12. import android.os.Bundle;  
  13. import android.os.IBinder;  
  14. import android.os.RemoteException;  
  15. import android.view.LayoutInflater;  
  16. import android.view.View;  
  17. import android.view.View.OnClickListener;  
  18. import android.view.ViewGroup;  
  19. import android.widget.BaseAdapter;  
  20. import android.widget.Button;  
  21. import android.widget.EditText;  
  22. import android.widget.ImageView;  
  23. import android.widget.ListView;  
  24. import android.widget.TextView;  
  25. import android.widget.Toast;  
  26.   
  27. import com.feixun.hu.ipc.service.IMyService;  
  28. import com.feixun.hu.ipc.service.Person;  
  29.   
  30. public class IpcClient extends Activity   
  31. {  
  32.       
  33.     private IMyService mIMyService;  
  34.     private ContactAdapter mContactAdapter;  
  35.     private Person mPerson;  
  36.     private Button mGetInfo;  
  37.     private ListView showView;    
  38.     private EditText mInputName;  
  39.     private List<Person> mPersons;  
  40.       
  41.     /** Called when the activity is first created. */  
  42.     @Override  
  43.     public void onCreate(Bundle savedInstanceState)   
  44.     {  
  45.         super.onCreate(savedInstanceState);  
  46.         setContentView(R.layout.main);  
  47.           
  48.         //获取各组件  
  49.         mGetInfo = (Button) findViewById(R.id.get);  
  50.         mInputName = (EditText) findViewById(R.id.person);  
  51.         showView = (ListView)findViewById(R.id.show);  
  52.           
  53.         //创建mPersons集合对象  
  54.         mPersons = new ArrayList<Person>();  
  55.           
  56.         //创建Intent,对应服务端注册的Intent  
  57.         Intent intent = new Intent();  
  58.         intent.setAction("com.feixun.hu.action.IPC_SERVICE");  
  59.         //绑定连接远程服务  
  60.         bindService(intent, conn, Service.BIND_AUTO_CREATE);  
  61.           
  62.         //为设置按钮绑定监听  
  63.         mGetInfo.setOnClickListener(new OnClickListener()   
  64.         {         
  65.             @Override  
  66.             public void onClick(View v)   
  67.             {  
  68.                 // TODO Auto-generated method stub  
  69.                 if(mInputName.getText() != null )  
  70.                 {  
  71.                     try   
  72.                     {  
  73.                         String personName = mInputName.getText().toString();  
  74.                           
  75.                         //得到来自远程的Person对象mPerson  
  76.                         mPerson = mIMyService.getPerson(personName);  
  77.                           
  78.                         if (mPerson != null)  
  79.                         {  
  80.                             getInfo(mPerson);  
  81.                         }  
  82.                     }   
  83.                     catch (RemoteException e)   
  84.                     {  
  85.                         // TODO Auto-generated catch block  
  86.                         e.printStackTrace();  
  87.                     }  
  88.                 }  
  89.             }  
  90.         });  
  91.           
  92.     }  
  93.       
  94.     //该方法实现在ListView显示从远程得到的相关信息  
  95.     private void getInfo(Person person)  
  96.     {  
  97.         //将从远程得到的mPerson对象添加入mPersons集合  
  98.         mPersons.add(person);     
  99.           
  100.         //通过远程得到的mPerson对象  
  101.         mContactAdapter = new ContactAdapter(this, mPersons);  
  102.         showView.setAdapter(mContactAdapter);  
  103.     }  
  104.       
  105.     //实现客户端与服务端绑定的关键部分  
  106.     private ServiceConnection conn = new ServiceConnection()   
  107.     {  
  108.         //解除连接服务端  
  109.         @Override  
  110.         public void onServiceDisconnected(ComponentName name)   
  111.         {  
  112.             // TODO Auto-generated method stub  
  113.             mIMyService = null;  
  114.         }  
  115.         //连接服务端  
  116.         @Override  
  117.         public void onServiceConnected(ComponentName name, IBinder service)   
  118.         {  
  119.             // TODO Auto-generated method stub  
  120.             /*此处实现获取通过IpcService的onBind方法返回的mServiceBinder对象的代理。 
  121.              * 参数service为绑定获得的远程服务IpcService的mServiceBinder对象, 
  122.              * 而调用IMyService.Stub的函数asInterface获取的是mServiceBinder对象的代理。 
  123.              */  
  124.             mIMyService = IMyService.Stub.asInterface(service);  
  125.         }  
  126.     };  
  127.   
  128.     @Override  
  129.     protected void onDestroy()   
  130.     {  
  131.         // TODO Auto-generated method stub  
  132.         super.onDestroy();  
  133.         //解除绑定  
  134.         unbindService(conn);  
  135.     }  
  136.       
  137.     //自定义适配器,然后将从远程得到的用户信息在ListView中显示  
  138.     class ContactAdapter extends BaseAdapter  
  139.     {  
  140.   
  141.         private List<Person> persons = null;  
  142.         private LayoutInflater inflater = null;  
  143.           
  144.         public ContactAdapter(Context context, List<Person> person)  
  145.         {  
  146.             inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  147.             persons = person;  
  148.             //Log.d("MainActivity", "FxAdapter()");  
  149.         }  
  150.           
  151.         @Override  
  152.         public int getCount() {  
  153.             // TODO Auto-generated method stub  
  154.             return persons.size();  
  155.         }  
  156.   
  157.         @Override  
  158.         public Object getItem(int position) {  
  159.             // TODO Auto-generated method stub  
  160.             return persons.get(position);  
  161.         }  
  162.   
  163.         @Override  
  164.         public long getItemId(int position) {  
  165.             // TODO Auto-generated method stub  
  166.             return 0;  
  167.         }  
  168.   
  169.         @Override  
  170.         public View getView(int position, View convertView, ViewGroup parent)  
  171.         {  
  172.             // TODO Auto-generated method stub  
  173.             //得到来自远程服务端的Person对象  
  174.             Person person = (Person)persons.get(position);  
  175.               
  176.             ImageView mPictureView = null;  
  177.             TextView mNameView = null;  
  178.             TextView mPhoneView = null;  
  179.               
  180.             if (convertView == null)  
  181.             {  
  182.                 convertView = inflater.inflate(R.layout.contact_list, null);  
  183.             }  
  184.               
  185.             mPictureView = (ImageView)convertView.findViewById(R.id.user_image);  
  186.             //显示头像  
  187.             mPictureView.setImageBitmap(person.getPictures().get(person.getName()));  
  188.             mNameView = (TextView)convertView.findViewById(R.id.name_id);  
  189.             //显示姓名  
  190.             mNameView.setText(person.getName());  
  191.             mPhoneView = (TextView)convertView.findViewById(R.id.phone_id);  
  192.             //显示手机号  
  193.             mPhoneView.setText(person.getPhone());  
  194.             return convertView;  
  195.         }  
  196.           
  197.     }  
  198. }  

     关于通过实现Parcelable接口来进行程跨进程传递复杂数据的实现就到此结束了,相关代码下载链接地址如下:

     http://download.csdn.net/detail/stevenhu_223/5676401

0 0