文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处:http://blog.csdn.net/flowingflying/
在之前的StockQuote远程服务的接口中的方法为double getQuote(String ticker);。在远程服务中的方法的数据类型支持原始类型(primitive),如int这类的;支持String、CharSequence;复杂是类型支持List、Map,但在使用中有一些限制;如果我们希望使用自定义的类作为类型,需要使用Parcelable。本笔记将学习如何通过Parcelable封装在远程服务中的方法调用中进行复杂的数据传递。
远程服务实际是进程间通信,因此在接口的连接中,并不是传递对象,而是向原始类型那样,复制数据。Java的对象实际是C中的指针,Java并非没有指针,而是除了primitive类型外,全部是指针,当都是指针时,开发者感觉不到指针和非指针的差异,有时会有错误的感觉,以为Java无指针。由于不同进程有各自的内存空间,另一个进程不能操控其他进程的内存空间,也就是不能操控其他进程内存空间的对象。client和远程服务建立了AIDL接口的连接,在操作时,将数据的内容整份进行传递,类似我们在socket中传递数据,我们传递数据的地址(指针/对象)是毫无意义的,我们必须传递数据的内容。
自定义的Parcelable类
Parcel是消息(数据和对象)的容器,可以在IBinder(即远程服务的连接)中传递。Parcel是Android中设计用于高性能的IPC传输,因此我们不要将Parcel数据直接写到物理存贮中,因为Parcel中某个数据的改变,会使得其他数据变得不可读。Parcelable则是接口,我们自定义的数据类型,需要实现该接口,才能作为Parcel在IBinder中传递。
下面的例子很简单,我们自定义的数据类型Person含有两个数据,一是int age,一是String name。
 public class Person implements Parcelable{ 
    //【1】自定义的类型具体包含的数据,本例为age和name。
     private int age = 0; 
     private String name = null; 
     
     @Override 
     public int describeContents() {  
         return 0; 
     } 
 
     /* 【2】要实现Parcelable接口,需要实现writeToParcel()和readFromParcel(),实现将对象(数据)写入Parcel,和从Parcel中读出对象。需要注意,写的顺序和读的顺序必须一致,因为Parcel类是快速serialization和deserialization机制,和bundle不同,没有索引机制,是线性的数据存贮和读取。 
      * 注意其中readFromParcel()并不是overrider,而是我们自己提供的方法,如果我们不提供,就要在 
      * private Person(Parcel in){ 
      *     age = in.readInt(); 
      *     name = in.readString(); 
      * } 
      * 鉴于实际的数据类型会比小例子复杂,以及便于代码阅读,我们仿照writeToParcel()的命名,给出readFromParcel() */ 
     @Override 
     public void writeToParcel(Parcel out, int flag) {  
         out.writeInt(age);            //先写入age
         out.writeString(name);   //其次写如name 
     } 
     
     public void readFromParcel(Parcel in){ 
         age = in.readInt();          //先读出age,保持与写同顺序
         name = in.readString();  //其次读出name,保持与写同顺序
     } 
 
    /* 【3】:提供构造函数,用于从Parcel中创建对象,也即是读的过程。这里设置为private,禁止外部调用 */
     private Person(Parcel in){ 
         readFromParcel(in); 
     }  
      
     // 这个构造函数,是方便我们在client中创新相关对象,并将之作为接口连接中调用方法的的参数 
     public Person(){    
     } 
     
    /* 下面是我们在自定义类中的自定义方法,本例简单提供age和name的读写 */ 
     public int getAge(){ 
         return age; 
     } 
     
     public String getName(){ 
         return name; 
     } 
     
     public void setAge(int age){ 
         this.age = age; 
     } 
     
     public void setName(String name){ 
         this.name = name; 
     }  
      
     /*【4】 实现Parcelable接口的类必须要有一个static field称为CREATOR,用于实现Parcelable.Creator接口的对象。在AIDL文件自动生成的Java接口中,IBinder将调用Parcelable.Creator来获得传递对象:_arg1 = cn.wei.flowingflying.proandroidservice.Person.CREATOR.createFromParcel(data);  */ 
     public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { 
         @Override 
         public Person createFromParcel(Parcel source) {  
             return new Person(source);  //见【3】
         } 
 
         @Override 
         public Person[] newArray(int size) {  
             return new Person[size]; 
         }          
     };  
       
 }
AIDL文件
我们定义Person.aidl对Parcelable进行说明,由于我们已经有一个Person.java,所以系统不会再自动生成相关的java代码。
 package cn.wei.flowingflying.proandroidservice; 
 parcelable Person;
当定义了Person.aidl中,我们可以在接口定义中使用该类型。在非原语类型,非String类型,其他的类型在接口中作为参数需要描述传递的方向in、out或者inout。
 package cn.wei.flowingflying.proandroidservice; 
 import cn.wei.flowingflying.proandroidservice.Person; 
 
 interface IStockQuoteService2{ 
     String getQuote(in String ticker, in Person  requester); 
 }
服务的实现
服务的实现和之前的远程服务没有什么区别,只是方法中数据类型的不同,下面是StockQuoteRemoteService2.java的片段,为了更好地和用户互动,Service会在通知栏上出现,详细可以下载我们的源代码进行查看。此外我们需要在AndroidManifest.xml中对service进行定义。
 public class StockQuoteRemoteService2 extends Service{  
     public class StockQuoteServiceImpl extends IStockQuoteService2.Stub{ 
         private int count = 0; 
         @Override 
         public String getQuote(String ticker, Person requester) throws RemoteException { 
             return "Hello " + requester.getName() + "! Quote for " + ticker + " is " + (20.0+(count++));
         } 
     } 
      
    ... ... 
 
     @Override 
     public IBinder onBind(Intent arg0) {  
         return new StockQuoteServiceImpl(); 
     } 
 }
Client的实现
我们新建一个project来作为client。这个client同样需要了解接口,了解接口中所涉及的parcelable Person的定义,因此我们需要将service中的IStockQuoteService2.aidl,Person.aidl以及Person.java拷贝过来。

和之前的client只是连接接口后,调用方法的参数不同,相关代码如下:
 public class MainActivity extends Activity { 
     private IStockQuoteService2 stockService2 = null;  
     … … 
     private ServiceConnection servConn = new ServiceConnection() {         
         @Override 
         public void onServiceDisconnected(ComponentName name) { 
             … …  
             stockService2 = null; 
         } 
         
        @Override 
         public void onServiceConnected(ComponentName name, IBinder service) { 
             … …  
             stockService2 = IStockQuoteService2.Stub.asInterface(service);         
         } 
     };     
     
 
     private void callService(){ 
         try{ 
             Person person = new Person(); 
             person.setAge(25); 
             person.setName("Flowingflying"); 
             String response = stockService2.getQuote("WEI", person); 
             Toast.makeText(this, response, Toast.LENGTH_LONG).show(); 
         }catch(RemoteException e){ 
             Log.e("Client2",e.toString()); 
         } 
     } 
 
 } 
 
同步和异步
这里学习的服务都是同步的,因为我们在UI thread中进行调用。如果service需要大量的运算,我们希望能够运行在后台,也就是client在后台线程中对服务进行调用。
本博文涉及的例子代码,可以在Pro Android学习:Android service小例子中下载。
相关链接: 我的Android开发相关文章
 Parcelable详解
 Parcelable详解
         
                   
                   
                   
                   
                            
 
                             本文详细介绍了如何在Android中使用Parcelable接口进行复杂数据类型的传递,包括自定义Parcelable类的具体步骤、AIDL文件配置、服务端及客户端实现。
本文详细介绍了如何在Android中使用Parcelable接口进行复杂数据类型的传递,包括自定义Parcelable类的具体步骤、AIDL文件配置、服务端及客户端实现。
           
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   1908
					1908
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            