在Android系统中,各应用程序都运行在自己的进程中,进程之间一般无法直接进行数据交换.为了实现这种跨进程通信(inter process communication,简称 IPC),Android提供了 AIDL Service.
Android中需要AIDL (Android Interface Definition Language)来定义远程接口.
AIDL语法和java接口很相似,但存在以下几点差异:
- AIDL 定义接口的源代码必须以 .aidl结尾.
- AIDL接口中用到数据类型,除了基本类型,String ,List ,Map,CharSequence之外,其他类型全部需要导包,即使它们在同一个包中也需要导包.
1.创建AIDL文件
// ICat.aidl
package com.test.service.aidlservice;
// Declare any non-default types here with import statements
interface ICat {
String getColor();
double getWeight();
}
义好AIDL文件后,ADT工具会自动在gen/com/example/aidlservice/目录下生成一个ICat.java接口,该类内部包含一个Stub内部类,实现了IBinder,ICat两个接口,这个Stub类会作为远程Service回调类;
2.将接口暴露给客户端
package com.test.service.aidlservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.Timer;
import java.util.TimerTask;
public class AidlService extends Service {
private CatBinder mCatBinder;
Timer mTimer = new Timer();
String[] colors = new String[]{"红色", "绿色", "蓝色"};
double[] weights = new double[]{3.3, 3.2, 1.68};
private String color;
private double weight;
public class CatBinder extends ICat.Stub {
@Override
public String getColor() throws RemoteException {
return color;
}
@Override
public double getWeight() throws RemoteException {
return weight;
}
}
@Override
public void onCreate() {
super.onCreate();
mCatBinder = new CatBinder(); //创建 CatBinder实例化对象
mTimer.schedule(new TimerTask() {
@Override
public void run() {
//随机的改变Service 组件内 color 和weight属性的值
int rand = (int) (Math.random()*3);
color = colors[rand];
weight = weights[rand];
Log.d("AidlService", "---rand---: "+rand);
}
},0,800);
}
@Override //必须实现的方法
public IBinder onBind(Intent intent) {
/**
* 返回 mCatBinder 对象
* 在绑定本地Service 的情况下,该 mCatBinder 对象会直接传给客户端的 ServiceConnection对象的 onServiceConnected 方 法的第2个参数;
*
* 在绑定远程service 的情况下,只将 mCatBinder 对象的代理传给客户端的 ServiceConnection对象的onServiceConnected方法的第2个参数;
*
*/
return mCatBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel();
}
}
在AndroidManifext.xml文件中配置该Service :
<intent-filter >
<action android:name="com.test.service.AIDL_SERVICE" />
</intent-filter>
3.客户端访问AIDLService
将Service端的AIDL文件复制到客户端中,注意要在相同的包名下。
`package com.test.aidlclient;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;import com.test.service.aidlservice.ICat;
public class AidlClientActivity extends AppCompatActivity {
private ICat catService;
Button get;
EditText color,weight;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取远程 Service的onBind方法返回的对象的代理
catService = ICat.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
catService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
get = (Button) findViewById(R.id.get);
color = (EditText) findViewById(R.id.color);
weight = (EditText) findViewById(R.id.weight);
//创建所需绑定的Svice 的 Intent
Intent intent = new Intent();
intent.setAction("com.test.service.AIDL_SERVICE");
intent.setPackage(this.getPackageName()); //为了兼容 5.0版本//绑定远程服务
bindService(intent,conn, Service.BIND_AUTO_CREATE);
get.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//获取远程服务Service的状态
try {
color.setText(catService.getColor());
weight.setText(catService.getWeight()+"");
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//解除 绑定服务
this.unbindService(conn);
}}
`
<客户端访问AIDL service>
AIDL 接口定义了两个进程之间的通信接口,因此不仅服务器端需要aidl接口,客户端需要定义aidl接口.因此开发客户端的第一步就是将Service端的aidl接口复制到客户端应用中,复制到客户端后ADT工具会aidl接口生成相应的实现.
客户端绑定远程service 与绑定本地service的区别并不大,同样是需要2步:
- 创建 ServiceConnection对象.
- 以 ServiceConnection对象作为参数,调用Context的 bindService()方法绑定远程Service 即可.
与绑定本地service的不同的是,绑定远程service 的ServiceConnection对象并不能直接获取Service的onBind()方法所返回的对象,它只能返回onBind()方法所返回的对象的代理,因此在 ServiceConnection的 onServiceConnected方法中需要通过如下代码进行代理:
catService = Icat.Stub.asInterface(service);