Android系统中进程间不能共享内存。为使其他APP共享本APP提供的服务,Android采用了RPC(Remote Procedure Call)。Android使用一种接口定义语言来公开服务的接口。我们知道Android4大组件中的3个(Activity、BroadcastReceiver、ContentProvider)都可跨进程访问,Service同样可以。我们将跨进程访问的服务称为AIDL服务。
AIDL的使用步骤:
1)创建Android项目,定义aidl文件IMyService.aidl,会在gen目录自动生成跟aidl文件相同包名的Java接口文件IMyService.java。
2)定义Service的子类,在其中定义继承IMyService.Stub的内部类MyServiceImpl。在onBind方法中返回MyServiceImpl的实例。
3)在清单文件注册该Service,其action标签name属性即该服务对外公开的action。
4)在另一个项目中绑定该服务并调用方法。
1、示例演示AIDL的用法
1)IMyService.aidl
package com.qinuli.aidltest.aidl;
interface IMyService{
String getValue();
}
2)IMyService.java,自动生成的接口文件
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\Users\\shixin\\workspace\\AIDLTest\\src\\com\\qinuli\\aidltest\\aidl\\IMyService.aidl
*/
package com.qinuli.aidltest.aidl;
public interface IMyService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.qinuli.aidltest.aidl.IMyService
{
private static final java.lang.String DESCRIPTOR = "com.qinuli.aidltest.aidl.IMyService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.qinuli.aidltest.aidl.IMyService interface,
* generating a proxy if needed.
*/
public static com.qinuli.aidltest.aidl.IMyService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.qinuli.aidltest.aidl.IMyService))) {
return ((com.qinuli.aidltest.aidl.IMyService)iin);
}
return new com.qinuli.aidltest.aidl.IMyService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getValue:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getValue();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.qinuli.aidltest.aidl.IMyService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.lang.String getValue() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getValue, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getValue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String getValue() throws android.os.RemoteException;
}
3)MyService.java
public class MyService extends Service {
public class MyServiceImpl extends IMyService.Stub{
@Override
public String getValue() throws RemoteException {
return "终于等到你";
}
}
@Override
public IBinder onBind(Intent intent) {
return new MyServiceImpl();
}
}
4)AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.qinuli.aidltest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service android:name="com.qinuli.aidltest.MyService">
<intent-filter >
<action android:name="com.qinuli.aidltest.aidl.IMyService"/>
</intent-filter>
</service>
</application>
</manifest>
5)MainActivity.java
public class MainActivity extends Activity{
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View v){
switch(v.getId()){
case R.id.btn_bind:
bindService(new Intent("com.qinuli.aidltest.aidl.IMyService"), mServiceConnection, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_call:
try {
Toast.makeText(this, myService.getValue(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
private IMyService myService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = IMyService.Stub.asInterface(service);
}
};
}
6)activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/btn_bind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="bind"
android:onClick="onClick"/>
<Button
android:id="@+id/btn_call"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="call"
android:onClick="onClick"/>
</LinearLayout>