Android学习笔记——AIDL跨进程服务的应用
Android 学习笔记
——AIDL:Android Interface Definition Language
今天学习并研究了Andriod接口定义语言。进行如下总结:
基本概念
Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。我们知道4个Android应用程序组件中的3个(Activity、Broadcast和Content Provider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。AIDL则充当在进程间访问远程service的桥梁,编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的。 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象。把.aidl文件保存到工程的src/目录中,在编译应用程序时,SDK工具会在工程的gen/目录中生成IBinder接口文件。生成的文件名与.aidl文件名相匹配,只是使用.java扩展名(例如,IRemoteService.aidl,生成结果是IRemoteService.java)。
创建aidl文件需要注意一下几点:
- 方法不需要修饰符(private、public、final等等)。
-
以下情况不需要import语句:
Java编程语言的主要类型 (int, boolean等)
String
List -列表中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。List可以像一般的类(例如List)那样使用,另一边接收的具体类一般是一个ArrayList,这些方法会使用List接口。
Map - Map中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。一般的maps(例如Map)不被支持,另一边接收的具体类一般是一个HashMap,这些方法会使用Map接口。
CharSequence -该类是被TextView和其他控件对象使用的字符序列。
-
通常引引用方式传递的其他AIDL生成的接口,必须要import 语句声明
-
方法能够带有0或多个参数,并且能够返回一个值或void
以下是aidl文件的编写规范:
具体步骤
1). 创建工程:
Client: package Name:com.taylor.client
Service: package Name:com.taylor.service
Demo功能:Service段提供两个可以返回String的方法。在Client点击Button得到远程service返回的String填写到Client端的TextView中。
2). 编写aidl文件
package com.taylor.aidl; interface Remote { String getValue() ; String getName() ; }
如果AIDL文件编写正确。在Eclipse下会自动在gen目录的下生成相同的包以及文件名相同的java文件。如图:
3). 接下来编写Service。实现aidl文件中声明的方法:
package com.taylor.service; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import com.taylor.aidl.Remote; /** * Created by sunhb on 7/9/13. */ public class MyService extends Service { //声明远程service对象,并实现在aidl中声明的方法: private Remote.Stub myAidl = new Remote.Stub() { @Override public String getValue() throws RemoteException { return "AIDL :getValue() ;"; } @Override public String getName() throws RemoteException { return "AIDL :getName() ;"; } } ; @Override public IBinder onBind(Intent intent) { //在bindService时返回远程service对象: return myAidl; } }
在编写上面代码时要注意如下两点:
Remote.Stub是根据Remote.aidl文件自动生成的,一般并不需要管这个类的内容,只需要编写一个继承于Remote.Stub类的子类即可。
onBind方法必须返回Remote.Stub类的对象实例,否则客户端无法获得服务对象。
4).在AndroidManif.xml文件中声明service
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.taylor.service" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.taylor.service.ServiceActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyService" android:process=":remote"> <intent-filter> <!-- AIDL完整路径名。必须指明,客户端能够通过AIDL类名查找到它的实现类 --> <action android:name="com.taylor.aidl.Remote" /> </intent-filter> </service> </application> </manifest>
至此Service端代码完成。
5).以完全相同的方式在Client的相同包名下编写完全相同的AIDL文件。在gen目录中得到java文件。此处不再赘述。如图:
6).在Client端完成远程服务的调用:
package com.taylor.client; import android.app.Activity; import android.content.ComponentName; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.taylor.aidl.Remote; public class ClientActivity extends Activity implements View.OnClickListener{ private static final String TAG = "TAG_AIDL" ; private TextView show ; private Button getValue ,getName ; //远程Service对象 private Remote myAidl ; //远程Service连接 private ServiceConnection connect = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //连接建立,通过下面方式实例化远程Service对象 myAidl = Remote.Stub.asInterface(iBinder) ; Log.d(TAG ,"Remote Service Connection...") ; } @Override public void onServiceDisconnected(ComponentName componentName) { myAidl = null ; Log.d(TAG ,"Remote Service Disconnect...") ; } } ; /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); show = (TextView)findViewById(R.id.show) ; getValue = (Button) findViewById(R.id.getValue); getName = (Button) findViewById(R.id.getName) ; getValue.setOnClickListener(this); getName.setOnClickListener(this); //BindService Intent service = new Intent (Remote.class.getName()) ; bindService(service ,connect ,BIND_AUTO_CREATE) ; } @Override public void onClick(View view) { String str = null ; try { switch (view.getId()){ case R.id.getName: str = myAidl.getName() ; Log.d(TAG ,"getName:"+str) ; show.setText(str); break ; case R.id.getValue: str = myAidl.getValue() ; show.setText(str); Log.d(TAG ,"getValue:"+str) ; break; } } catch (RemoteException e) { e.printStackTrace(); } } }
好了,到这里就已经将Demo的功能完成了。试着运行一下:
点击“getValue”
点击“getName”
总觉得学习要留下痕迹,知识需要积累,才会从量变转化为质变,当然更希望我的痕迹,能帮助到别人。于是我觉得把我学习的脚步记录下来。这是第一篇。如有遗漏或错误之处欢迎指正。