概念
在Android上一个进程通常是无法访问另一个进程的内存,而AIDL翻译过来就是Android 接口定义语言,你可以你利用它定义客户端和服务端进程间通信相互认可的编程接口。
适用范围
只有允许不同应用的客户端用IPC方式访问服务,并且想要在服务中处理多线程问题时,才有必要适用AIDL。如果想执行IPC,但不需要处理多线程,可以考虑使用Messenger类实现。如果不需要执行跨不同应用的并发IPC,可以通过实现一个Binder来实现。
使用
考虑这样一个场景:client 客户端跨进程访问 server 客户端,流程如下
server 客户端接受请求通知,访问远程服务器返回数据,并将数据通知给client 客户端 , 下面我们来看看如何一步步实现该功能
创建server 客户端
1、创建.aidl文件
新建一个名为server的工程,这里面我们创建三个aidl文件
IRomteService.aidl 定义请求接口
ICallBack.aidl 自定义回调接口
MyBean.aidl 自定义的对象
MyBean.java 自定义对象类(必须实现Parcelable接口)
注意:MyBean.aidl和MyBean.java要保证在同一个包路径下
// IRomteService.aidl
package com.aidlserver.myaidl;
import com.aidlserver.myaidl.MyBean;
import com.aidlserver.myaidl.ICallBack;
// Declare any non-default types here with import statements
interface IRemoteService {
void requestServer(in MyBean param, in ICallBack callback);
}
// MyBean.aidl
package com.aidlserver.myaidl;
import com.aidlserver.myaidl.MyBean;
// Declare any non-default types here with import statements
parcelable MyBean;
// ICallBack.aidl
package com.aidlserver.myaidl;
// Declare any non-default types here with import statements
interface ICallBack {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void onResult(String result);
}
package com.aidlserver.myaidl;
import android.os.Parcel;
import android.os.Parcelable;
public class MyBean implements Parcelable {
public int mId;
public String mName;
public MyBean() {
}
protected MyBean(Parcel in) {
readFromParcel(in);
}
public static final Creator<MyBean> CREATOR = new Creator<MyBean>() {
@Override
public MyBean createFromParcel(Parcel in) {
return new MyBean(in);
}
@Override
public MyBean[] newArray(int size) {
return new MyBean[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mId);
dest.writeString(mName);
}
public void readFromParcel(Parcel in) {
mId = in.readInt();
mName = in.readString();
}
@Override
public String toString() {
return "id:" + mId + " name:" + mName;
}
}
2、创建Service(关键部分)
创建一个RemoteService服务,它是连接外部应用和远程服务器的枢纽,代码如下
package com.aidlserver.service;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import com.aidlserver.myaidl.ICallBack;
import com.aidlserver.myaidl.IRemoteService.Stub;
import com.aidlserver.myaidl.MyBean;
public class RemoteService extends Service {
private static final String TAG = RemoteService.class.getSimpleName();
private static final String CLIENT_PACKAGE_NAME = "com.client";
private static final String MYSELF_PACKAGE_NAME = "com.aidlserver";
private Object mLock = new Object();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, TAG + "onCreate");
}
private Stub mBinder = new Stub() {
@Override
public void requestServer(MyBean param, final ICallBack callback) throws RemoteException {
synchronized (mLock) {
//模拟耗时请求开启线程请求服务端
Log.d(TAG, "requestServer param:" + param.toString());
new Thread(new Runnable() {
@Override
public void run() {
if (callback != null) {
try {
callback.onResult("I was server response . hello client");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
//该方法可以对外部应用做认证
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
String[] stringArray = RemoteService.this.getPackageManager().getPackagesForUid(getCallingUid());
String packageName = null;
if (stringArray != null && stringArray.length > 0) {
packageName = stringArray[0];
}
boolean result = false;
//只有"com.client"应用及其自己能访问
if (!CLIENT_PACKAGE_NAME.equals(packageName)
&& !MYSELF_PACKAGE_NAME.equals(packageName)) {
result = false;
} else {
result = super.onTransact(code, data, reply, flags);
}
Log.d(TAG, "packageName:" + packageName + " result:" + result);
return result;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "=====onBind=====");
//返回自定义的IRemoteService的存根(Sub)
return mBinder;
}
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.d(TAG, "=====unbindService=====");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "=====onDestroy=====");
}
}
3、注册Service
在清单文件加入如下代码
<application>
<service
android:name=".service.RemoteService"
android:enabled="true"
android:exported="true"
android:process=":remote"
></service>
</application>
4、编写客户端调用代码
新建一个Activity,
完整Activity代码如下,
package com.aidlserver;
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.Process;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.aidlserver.myaidl.ICallBack;
import com.aidlserver.myaidl.IRemoteService;
import com.aidlserver.myaidl.MyBean;
import com.aidlserver.service.RemoteService;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private Button mBtnBindService;
private Button mBtnUnbindService;
private TextView mTextView;
private ServiceConnection mServiceConnection;
private boolean mIsBinded = false;
private IRemoteService mRomteService;
/**
* 请求回调存根
*/
private ICallBack.Stub mCallBack = new ICallBack.Stub() {
//回调通知结果
@Override
public void onResult(final String result) throws RemoteException {
Log.d(TAG, "client onResult function run in " + Process.myPid() + " Process" + "thread:" + Thread.currentThread().getName());
mTextView.post(new Runnable() {
@Override
public void run() {
mTextView.setText(result);
}
});
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定服务按钮
mBtnBindService = (Button) findViewById(R.id.btn_bind_service);
mBtnBindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//绑定服务
Intent intent = new Intent(MainActivity.this, RemoteService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
//5.0以后必须都是显式绑定,隐式绑定会报错,如果是外部应用调用可以使用下面注释代码,绑定服务
/**
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.aidlserver", "com.aidlserver.service.RemoteService"));
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
*/
}
});
//解绑服务按钮
mBtnUnbindService = (Button) findViewById(R.id.btn_unbind);
mBtnUnbindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mIsBinded && mRomteService != null) {
//解绑服务
unbindService(mServiceConnection);
mIsBinded = false;
mTextView.setText("unbinded");
}
}
});
mTextView = (TextView) findViewById(R.id.tv_content);
mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, final IBinder service) {
Log.d(TAG, "service connected");
mTextView.setText("onServiceConnected");
mIsBinded = true;
mRomteService = IRemoteService.Stub.asInterface(service);
MyBean param = new MyBean();
param.mId = 123;
param.mName = "I was android client";
try {
//开始请求
mRomteService.requestServer(param, mCallBack);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mIsBinded = false;
mRomteService = null;
mTextView.setText("unBind");
Log.d(TAG, "onServiceDisconnected");
}
};
}
}
现在我们运行server app 效果如下:
创建Client 客户端
client客户端代码就比较简单了,
我们只要把server工程里面
ICallBack.aidl
IRemoteService.aidl
MyBean.aidl
MyBean.java移到和server同一个包路径就可以了,
client客户端调用的activity和server客户端的activity几乎一样
源码下载:
AIDL Demo