##前言
模拟:我们需要外部进程服务提供一个计算地点横纵坐标的方法来显示到我们自己的Textview上。
##步骤
###第一步创建相对应Aidl文件与需要自定义的类型
####创建自定义类型
首先新建一个项目
这里我们需要定义一个自定义类型LocationData 为了记录横众坐标与服务Pid,创建!
LocationData.java 实现ParceLable借口,代码注释挺明白。具体可另行百度。
public class LocationData implements Parcelable {
int width;//代表横
int heigth;//代表纵
public LocationData(){
}
public LocationData(Parcel in){
readFromParcel(in);//对象通过Binder从Parcel返回拿到
}
@Override
public int describeContents() {
return 0;//描绘类型信息一般不用管
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(width);//数据写入容器Parcel
dest.writeInt(heigth);
}
public static final Creator<LocationData> CREATOR = new Creator<LocationData>() {
//内部类实现对象反序列化
@Override
public LocationData createFromParcel(Parcel in) {
return new LocationData(in);
}
@Override
public LocationData[] newArray(int size) {
return new LocationData[size];
}
};
/** 从Parcel中读取数据 **/
public void readFromParcel(Parcel in){
width = in.readInt();
heigth = in.readInt();
}
public int getHeigth() {
return heigth;
}
public void setHeigth(int heigth) {
this.heigth = heigth;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
@Override
public String toString() {
return "width = "+ width + ", heigth="+ heigth;
}
}
自定义类型LocationData.aidl文件很简单无需过多声明只要声明出类型即可。
AS2.2创建Aidl文件
LocationData.aidl
package com.ljs.testfitsystem;
parcelable LocationData;
默认Aidl支持原生类型只支持如下,所以需要我们自定义类型。
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
为什么自定义类型需要从新定义adil呢,可见如下blog。
http://blog.csdn.net/luojiusan520/article/details/52862202
####声明创建aidl接口
// IMyAidlInterface.aidl
package com.ljs.aidltest;
import com.ljs.aidltest.LocationData;// 导入自定义类型
// Declare any non-default types here with import statements
interface IMyAidlInterface {
int getPid();//获得当前服务进程ID
LocationData getMyData();//提供LocationData对象给予我们Client
}
得到我们接口文件。内部含1个内部类stub。stub内部含有Proxy类。具体就是对Binder的一些控制与数据操作,由于此文件自动生成,我们也不需要过多关心。
###编写RPC中的远程服务,
####创建RemoteService.java 继承service,
这里我们为了模拟跨进程通信使用 android:process=“”来替代生成一个IPC通信的远程服务。
<service android:name=".RemoteService"
android:process=":server"> //随意设置只是一个进程名称
<intent-filter>
<action android:name="com.ljs.adiltest"></action>//用来启动服务
</intent-filter>
</service>
具体service文件如下已经作注释:
public class RemoteService extends Service {
private static final String TAG = "server"; //Log观察生命周期
LocationData mMyData;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "[server] onCreate");
initMyData();//初始化Location
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"[server] onBind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "[server] onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i(TAG, "[server] onDestroy");
super.onDestroy();
}
//通过Aidl生成文件中Stub类实现我们生成接口中的方法
IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public int getPid() throws RemoteException {
Log.i(TAG,"[server] getPid()="+android.os.Process.myPid());
return android.os.Process.myPid();
}
@Override
public LocationData getMyData() throws RemoteException {
Log.i(TAG,"[server] getMyData() "+ mMyData.toString());
return mMyData;
}
//Binder驱动底层调用传送数据,由于server ,1对多,一般不设置也可以做权限设置,判断是否需要传递速度给Client。
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return super.onTransact(code, data, reply, flags);
}
};
/**
* 初始化MyData数据
**/
private void initMyData() {
mMyData = new LocationData();
mMyData.setWidth((int)(Math.random()*100));//随机给予位置信息
mMyData.setHeigth((int)(Math.random()*100));
}
}
###客户端编写
得到接口,服务端准备好,我们客户端Bind服务就可以进行IPC通信了。
####client编写
MainActivity.java 重要部分已经注释
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Client";
private IMyAidlInterface mRemoteService;
private boolean mIsBound =false;//是否已经绑定
private TextView mTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "[Client] onCreate");
setContentView(R.layout.activity_main);
mTv = (TextView) findViewById(R.id.tv);
mTv.setText("还未连接");
}
//监控远程服务状态链接,ServiceConnection
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteService = IMyAidlInterface.Stub.asInterface(service);//链接上了才会调用
String pidInfo = null;
try {
LocationData myData = mRemoteService.getMyData();
pidInfo ="客户端Pid"+ Process.myPid()+
"服务Pid="+ mRemoteService.getPid() +
", 横坐标 = "+ myData.getWidth() +
", 纵坐标="+ myData.getHeigth();
} catch (RemoteException e) {
e.printStackTrace();
}
Log.i(TAG, "[Client] onServiceConnected "+pidInfo);
mTv.setText(pidInfo);
Toast.makeText(MainActivity.this, "绑定上了哦", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
//正常顺序默认不调用意外情况销毁调用
Log.i(TAG, "[Client] onServiceDisconnected");
mTv.setText("服务与客户端断开");
mRemoteService = null;
Toast.makeText(MainActivity.this, "已经断开服务", Toast.LENGTH_SHORT).show();
}
};
public void clickButton(View view){
switch (view.getId()){
case R.id.btn_bind:
bindRemoteService();
break;
case R.id.btn_unbind:
unbindRemoteService();
break;
case R.id.btn_kill:
killRemoteService();
break;
}
}
//绑定远程服务
private void bindRemoteService(){
Log.i(TAG, "[Client] bindRemoteService");
Intent intent = new Intent(MainActivity.this, RemoteService.class);
intent.setAction("com.ljs.adiltestAction");
intent.setPackage(getPackageName());//Android5.0不允许直接隐式启动,需要加包名
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
mTv.setText("开始绑定服务");
}
//解除绑定
private void unbindRemoteService(){
Log.i(TAG, "[Client] unbindRemoteService ==>");
if(!mIsBound){
Toast.makeText(MainActivity.this, "不需要解绑已经没有绑定服务", Toast.LENGTH_SHORT).show();
return;
}
unbindService(mConnection);
mIsBound = false;
mTv.setText("解除绑定服务");
}
//kill远程服务
private void killRemoteService(){
Log.i(TAG, "[Client] killRemoteService");
try {
android.os.Process.killProcess(mRemoteService.getPid());
mTv.setText("Kill掉远程服务所在进程");
Toast.makeText(MainActivity.this, "远程服务杀掉了哦", Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "服务进程不存在,杀死服务进程失败", Toast.LENGTH_SHORT).show();
}
}
}
###程序Bind服务调用服务方法接口获得服务端随机算出来的LocationData对象与服务进程Pid截图
###依次执行生成Log信息
Client下顺序
2570-2570/com.ljs.aidltest I/Client: [Client] onCreate
2570-2570/com.ljs.aidltest I/Client: [Client] bindRemoteService
2570-2570/com.ljs.aidltest I/Client: [Client] onServiceConnected 客户端Pid2570服务Pid=3579, 横坐标 = 31, 纵坐标=8
2570-2570/com.ljs.aidltest I/Client: [Client] unbindRemoteService ==>
2570-2570/com.ljs.aidltest I/Client: [Client] killRemoteService
server下顺序
3579-3579/com.ljs.aidltest:Remoteserver I/Server: [server] onCreate
3579-3579/com.ljs.aidltest:Remoteserver I/Server: [server] onBind
3579-3592/com.ljs.aidltest:Remoteserver I/Server: [server] getMyData() width = 31, heigth=8
3579-3591/com.ljs.aidltest:Remoteserver I/Server: [server] getPid()=3579
3579-3579/com.ljs.aidltest:Remoteserver I/Server: [server] onUnbind
3579-3579/com.ljs.aidltest:Remoteserver I/Server: [server] onDestroy
###Github具体源代码地址
https://github.com/anderson9/AIDLnewDemo