1. 引言:
(1)AIDL的作用
在Android平台,每个应用程序都是一个单独的JVM,都运行在自己的进程空间里, 通常,一个进程不允许访问另一个进程的内存空间(一个应用不能访问另一个应用)。当用户(程序开发人员)想在一个App中访问另一个App的进程空间的时候,就需要进程间通信。在Android中,远程服务为我们提供了实现进程间通信的方式,其中,AIDL是应用程序开发人员常的一种方式。
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参 数。换句比较浅显的话来说,就是我这个App应用的activity,需要调用其他App应用的Service.当然同一App应用的activity
与service也可以在不同进程间,这可以设置Service配置中,android:process=":remote"。
可以看出,aidl的适用场景为: 只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service时,你可以使用AIDl来实现。例如,百度地图给我们提供了下面的service:com.baidu.location.f,我们只要在我们的应用程序的manifest.xml文件中声明这个service,就能用它提供的服务了。:
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>
2. 本篇主要实例:
应用服务之远程(remote)服务的开启和运用,也就是AIDL的创建和使用过程:
例子说明:
(1). 功能: 创建remote service,在service中计算出指定路径下有多少个文件,并在UI显示。
(2). 您将学到: a. remote service的定义和使用;
b. Aidl文件的定义和使用。
创建过程:
(1)在工程的src下,新建立一个文本文件,将要实现的函数放在这个文件中,后缀为.aidl。
(2)刷新工程后,就会发现在gen包下,有一个同名的java文件,这是aidl工具自动生成的,里面,就有我们要实现的函数。
(3)Aidl定义好后,我们就要实现我们的remote service了。它也是继承自service的。
(4)Service实现后,要将它在mainfest.xml设置为remote.注意,客户端服务端在同个App中,android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
(5)最后,来实现我们的客户端,也就是Activity,来调用service。
3. 例子代码:
(1).aidl文件:IFileCountService.aidl:
package com.example.remoteservicetest;
interface IFileCountService{
int getFileCnt(String path);
}
(2). remote service的实现:MyRemoteService.java:
package com.example.remoteservicetest;
import java.io.File;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class MyRemoteService extends Service {
static final String TAG="MyService";
private int fileCnt = 0;
//定义内部类MyRemoteServiceImpl,继承我们的AIDL文件自动生成的内部类,
//并且实现我们AIDL文件定义的接口方法
private class MyRemoteServiceImpl extends IFileCountService.Stub{
@Override
public int getFileCnt(String path) throws RemoteException {
Log.e(TAG, "path");
File file = new File(path);
if (file.exists()) {
if (file.isDirectory()) {
File files[] = file.listFiles();
if (files == null ) {
return 0;
}
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
fileCnt++;
}
}
}
}
return fileCnt;
}
}
@Override
public IBinder onBind(Intent arg0) {
//返回AIDL实现
return new MyRemoteServiceImpl();
}
@Override
public void onDestroy(){
Log.e(TAG, "Release MyService");
super.onDestroy();
}
}
(3). 客户端Activity:AndroidRemoteActivity.java:
package com.example.androidservicetest;
import com.example.remoteservicetest.IFileCountService;
import com.example.remoteservicetest.MyRemoteService;
import android.app.Activity;
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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class AndroidRemoteActivity extends Activity {
static final String TAG="AndroidRemoteActivity";
int fileCnt = 0;
private TextView textView;
Button btn1;
Button btn2;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.textview);
btn1 = (Button)findViewById(R.id.button1);
btn2 = (Button)findViewById(R.id.button2);
btn2.setVisibility(View.GONE);
btn1.setText("Get File Count:");
if(btn1!=null)
btn1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
//绑定一个服务
fileCnt = 0;
bindService();
}
});
}
IFileCountService iService=null;
private ServiceConnection conn=new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//返回AIDL接口对象,然后可以调用AIDL方法
iService=IFileCountService.Stub.asInterface(service);
try {
fileCnt=iService.getFileCnt("/sdcard");
}
catch (RemoteException e) {
Log.e(TAG,"error 000");
e.printStackTrace();
}
Log.e(TAG, "file count:"+fileCnt);
textView.setText("file count:"+fileCnt);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected");
}
};
private void bindService(){
Intent intent=new Intent(this,MyRemoteService.class);
startService(intent);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
}
(4). AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidservicetest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.androidservicetest.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.androidservicetest.AndroidLocalServiceActivity" >
</activity>
<activity
android:name="com.example.androidservicetest.AndroidRemoteActivity" >
</activity>
<service android:name="com.example.androidservicetest.PackageFindService" >
<intent-filter>
<action android:name="com.test.service"/>
</intent-filter>
</service>
<service android:name="com.example.remoteservicetest.MyRemoteService"
android:process=":remote"
>
<intent-filter>
<action android:name="com.example.remoteservicetest.IFileCountService"/>
</intent-filter>
</service>
</application>
</manifest>
4. 测试结果:
运行程序后,会显示两个button,第一个是测试locel service的,第二个是测试remote service的,点第二个,再点,就会在屏幕上显示sdcard根目录的文件个数了。
5. 代码下载:
http://download.csdn.net/detail/liranke/8401933