我的Android进阶之旅------>Android Service学习之AIDL, Parcelable和远程服务实例

通过上一篇(Android Service学习之AIDL, Parcelable和远程服务)的介绍,这一篇写一个小实例来实践一下

step1:建立两个应用,分别为RemoteService和RemoteServiceClient

                                       


先编写服务器端的内容

step2:开始编写一个StudentQuery.aidl文件

     AIDL(Android Interface Definition Language),用来定义远程接口。AIDL接口定义语言的语法十分简单,这种接口定义语言并不是一种真正的编程语言,它只是定义两个进程之间的通信接口,因此语法非常简单。AIDL的语法与Java接口很相似,但是也存在以下几点差异:

  • AIDL定义接口的源代码必须以 .aidl 结尾
  • AIDL接口中用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其他类型全部都需要导入包,即使它们在同一个包中也需要导包。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package cn.roco.aidl;  
  2.   
  3. interface StudentQuery {  
  4.     String queryStudent(int number);  
  5. }  

系统会根据此aidl文件生成一个类StudentQuery.java接口

StudentQuery接口中包含一个Stub内部类,该内部类实现了IBinder和StudentQuery接口,这个Stub类将会作为远程Service的回调类,它实现了IBinder接口,因此可以作为Service的onBind()方法的返回值。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /* 
  2.  * This file is auto-generated.  DO NOT MODIFY. 
  3.  * Original file: C:\\Documents and Settings\\student\\android\\RemoteService\\src\\cn\\roco\\aidl\\StudentQuery.aidl 
  4.  */  
  5. package cn.roco.aidl;  
  6. public interface StudentQuery extends android.os.IInterface  
  7. {  
  8. /** Local-side IPC implementation stub class. */  
  9. public static abstract class Stub extends android.os.Binder implements cn.roco.aidl.StudentQuery  
  10. {  
  11. private static final java.lang.String DESCRIPTOR = "cn.roco.aidl.StudentQuery";  
  12. /** Construct the stub at attach it to the interface. */  
  13. public Stub()  
  14. {  
  15. this.attachInterface(this, DESCRIPTOR);  
  16. }  
  17. /** 
  18.  * Cast an IBinder object into an cn.roco.aidl.StudentQuery interface, 
  19.  * generating a proxy if needed. 
  20.  */  
  21. public static cn.roco.aidl.StudentQuery asInterface(android.os.IBinder obj)  
  22. {  
  23. if ((obj==null)) {  
  24. return null;  
  25. }  
  26. android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
  27. if (((iin!=null)&&(iin instanceof cn.roco.aidl.StudentQuery))) {  
  28. return ((cn.roco.aidl.StudentQuery)iin);  
  29. }  
  30. return new cn.roco.aidl.StudentQuery.Stub.Proxy(obj);  
  31. }  
  32. public android.os.IBinder asBinder()  
  33. {  
  34. return this;  
  35. }  
  36. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  37. {  
  38. switch (code)  
  39. {  
  40. case INTERFACE_TRANSACTION:  
  41. {  
  42. reply.writeString(DESCRIPTOR);  
  43. return true;  
  44. }  
  45. case TRANSACTION_queryStudent:  
  46. {  
  47. data.enforceInterface(DESCRIPTOR);  
  48. int _arg0;  
  49. _arg0 = data.readInt();  
  50. java.lang.String _result = this.queryStudent(_arg0);  
  51. reply.writeNoException();  
  52. reply.writeString(_result);  
  53. return true;  
  54. }  
  55. }  
  56. return super.onTransact(code, data, reply, flags);  
  57. }  
  58. private static class Proxy implements cn.roco.aidl.StudentQuery  
  59. {  
  60. private android.os.IBinder mRemote;  
  61. Proxy(android.os.IBinder remote)  
  62. {  
  63. mRemote = remote;  
  64. }  
  65. public android.os.IBinder asBinder()  
  66. {  
  67. return mRemote;  
  68. }  
  69. public java.lang.String getInterfaceDescriptor()  
  70. {  
  71. return DESCRIPTOR;  
  72. }  
  73. public java.lang.String queryStudent(int number) throws android.os.RemoteException  
  74. {  
  75. android.os.Parcel _data = android.os.Parcel.obtain();  
  76. android.os.Parcel _reply = android.os.Parcel.obtain();  
  77. java.lang.String _result;  
  78. try {  
  79. _data.writeInterfaceToken(DESCRIPTOR);  
  80. _data.writeInt(number);  
  81. mRemote.transact(Stub.TRANSACTION_queryStudent, _data, _reply, 0);  
  82. _reply.readException();  
  83. _result = _reply.readString();  
  84. }  
  85. finally {  
  86. _reply.recycle();  
  87. _data.recycle();  
  88. }  
  89. return _result;  
  90. }  
  91. }  
  92. static final int TRANSACTION_queryStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);  
  93. }  
  94. public java.lang.String queryStudent(int number) throws android.os.RemoteException;  
  95. }  


step3:编写服务类StudentQueryService.java

该Service实现类的onBind()方法所返回的IBinder对象应该是的StudentQuert.Stub的子类的实例。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package cn.roco.remote.service;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6.   
  7. public class StudentQueryService extends Service {  
  8.     private String[] names = new String[100];  
  9.     private IBinder binder = new StudentQueryBinder();  
  10.   
  11.     @Override  
  12.     public IBinder onBind(Intent intent) {  
  13.         return binder;  
  14.     }  
  15.   
  16.     /** 
  17.      * 通过学号查询学生姓名 
  18.      *  
  19.      * @param no 
  20.      * @return 
  21.      * @throws Exception 
  22.      */  
  23.     public String query(int no) {  
  24.         if (no > 0 && no < names.length + 1) {  
  25.             return names[no - 1];  
  26.         } else {  
  27.             return null;  
  28.         }  
  29.     }  
  30.   
  31.     /** 
  32.      * 创建服务的时候做初始化操作 
  33.      */  
  34.     @Override  
  35.     public void onCreate() {  
  36.         for (int i = 0; i < names.length; i++) {  
  37.             names[i] = "RemoteQuery_" + (i + 1);  
  38.         }  
  39.         super.onCreate();  
  40.     }  
  41.   
  42.     /** 
  43.      * 关闭服务的时候,释放资源 
  44.      */  
  45.     @Override  
  46.     public void onDestroy() {  
  47.         for (int i = 0; i < names.length; i++) {  
  48.             names[i] = null;  
  49.         }  
  50.     }  
  51.     /** 
  52.      * cn.roco.aidl.StudentQuery.Stub 由系统根据StudentQuery.aidl自动生成 
  53.      */  
  54.     private final class StudentQueryBinder extends  
  55.             cn.roco.aidl.StudentQuery.Stub {  
  56.         @Override  
  57.         public String queryStudent(int number) {  
  58.             return query(number);  
  59.         }  
  60.     }  
  61. }  

step4:在AndroidManifest.xml文件中配置此服务

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="cn.roco.remote.service"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.     <uses-sdk android:minSdkVersion="8" />  
  7.   
  8.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  9.         <service android:name=".StudentQueryService" >  
  10.             <intent-filter>  
  11.                 <action android:name="cn.roco.remote.service.student.query"/>  
  12.             </intent-filter>  
  13.         </service>  
  14.     </application>  
  15. </manifest>  


编写完服务器端的代码后,编写客户端的代码

step5:在客户端也要讲StudentQuery.aidl文件导入到客户端中


step6:设计客户端的UI界面,main.xml文件

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent">  
  5.     <TextView android:layout_width="fill_parent"  
  6.         android:layout_height="wrap_content" android:text="@string/student_no" />  
  7.   
  8.     <EditText android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content" android:id="@+id/student_no" />  
  10.   
  11.     <Button android:layout_width="fill_parent"  
  12.         android:layout_height="wrap_content" android:text="@string/button_query"  
  13.         android:id="@+id/button_query" />  
  14.           
  15.     <TextView android:layout_width="fill_parent"  
  16.         android:layout_height="wrap_content" android:id="@+id/resultView" />  
  17.   
  18. </LinearLayout>  

string.xml文件

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <string name="hello">Hello World, MainActivity!</string>  
  4.     <string name="app_name">远程学生查询系统</string>  
  5.     <string name="student_no">学号</string>  
  6.     <string name="button_query">查询</string>  
  7. </resources>  


step7:客户端访问AIDLService

客户端绑定远程Service与绑定本地Service区别不大,同样之需要两步。

  • 1.创建ServiceConnection对象。
  • 2.以ServiceConnection对象作为参数,调用Context的bindService()方法绑定远程Service即可。

     与绑定本地Service不同的是,绑定远程Service的ServiceConnection并不能直接获取Service的onBind()方法所返回的对象,它只能返回onBind()方法所返回的对象的代理因此在ServiceConnection的onServiceConnected方法中需要通过如下代码进行处理:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // 调用该方法将远程的IBinder转换  
  2.             studentQuery = cn.roco.aidl.StudentQuery.Stub.asInterface(service);  


MainActivity.java文件

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">package cn.roco.remoteservice.client;  
  2.   
  3. import cn.roco.aidl.StudentQuery;  
  4. import android.app.Activity;  
  5. import android.content.ComponentName;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Bundle;  
  9. import android.os.IBinder;  
  10. import android.view.View;  
  11. import android.widget.Button;  
  12. import android.widget.EditText;  
  13. import android.widget.TextView;  
  14. import android.widget.Toast;  
  15.   
  16. public class MainActivity extends Activity {  
  17.     private EditText student_no;  
  18.     private TextView resultView;  
  19.     private ServiceConnection conn = new StudentServiceConnection();  
  20.     private StudentQuery studentQuery;  
  21.   
  22.     /** Called when the activity is first created. */  
  23.     @Override  
  24.     public void onCreate(Bundle savedInstanceState) {  
  25.         super.onCreate(savedInstanceState);  
  26.         setContentView(R.layout.main);  
  27.           
  28.         resultView = (TextView) findViewById(R.id.resultView);  
  29.         student_no = (EditText) findViewById(R.id.student_no);  
  30.         Button button_query = (Button) findViewById(R.id.button_query);  
  31.         button_query.setOnClickListener(new ButtonClickListener());  
  32.         /** 
  33.          *  该Intent是RemoteService项目中的Service 
  34.          *  "cn.roco.remote.service.student.query"为 
  35.          *  <service android:name=".StudentQueryService" > 
  36.                 <intent-filter> 
  37.                     <action android:name="cn.roco.remote.service.student.query"/> 
  38.                 </intent-filter> 
  39.             </service> 
  40.          */  
  41.         Intent service = new Intent("cn.roco.remote.service.student.query");  
  42.         // 绑定服务  
  43.         bindService(service, conn, BIND_AUTO_CREATE);  
  44.     }  
  45.   
  46.     @Override  
  47.     protected void onDestroy() {  
  48.         unbindService(conn); // 解绑服务  
  49.         super.onDestroy();  
  50.     }  
  51.   
  52.     /** 
  53.      * 该类中的两个方法都是回调函数 
  54.      */  
  55.     private class StudentServiceConnection implements ServiceConnection {  
  56.         @Override  
  57.         public void onServiceConnected(ComponentName name, IBinder service) {  
  58.             // 调用该方法将远程的IBinder转换  
  59.             studentQuery = cn.roco.aidl.StudentQuery.Stub.asInterface(service);   //重点理解  
  60.         }  
  61.   
  62.         @Override  
  63.         public void onServiceDisconnected(ComponentName name) {  
  64.             studentQuery=null;  
  65.         }  
  66.   
  67.     }  
  68.   
  69.     private final class ButtonClickListener implements View.OnClickListener {  
  70.         @Override  
  71.         public void onClick(View v) {  
  72.             String studentNo = student_no.getText().toString();  
  73.             String studentName;  
  74.             try {  
  75.                 studentName = studentQuery.queryStudent(Integer  
  76.                         .parseInt(studentNo));  
  77.                 if (studentName!=null) {  
  78.                     resultView.setText(studentName);  
  79.                 }else{  
  80.                     Toast.makeText(getApplicationContext(), "您输入的学号不在规定的学号内,请输入1到100的数字"1).show();  
  81.                 }  
  82.             } catch (Exception e) {  
  83.                 e.printStackTrace();  
  84.             }  
  85.         }  
  86.   
  87.     }  
  88. }</span>  



step8:将服务和客户端安装完后,查看运行的效果

             


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值