1)概述
本章是接着上篇没有写完的Bound式服务写的,上篇地址Android服务Service(二)。在此,重新回顾下AIDL基本概念,AIDL(Android Interface Definition Language)安卓接口描述语言,它专门用来处理进程通信,不像Messenger那样,它适合用来处理并发请求,如果你想service能够同时处理多个请求,那么就可以直接用AIDL。小小提下,Messenger底层也是AIDL,只不过系统为我们做了一层封装,方便我们调用。
2)AIDL
下面结合官方文档样例,具体介绍下怎么使用AIDL实现IPC进程通信,
2.1)AIDL接口文件的创建
我们看下图
AS中提供了AIDL文件的创建,但是我们也可以自己创建一个文件,改下后缀就行了。
我们看下生成的AIDL文件,和我实现的接口
我们可以看见在src/main下自动生成了一个aidl文件夹,这和eclipse不同,创建的AIDL文件就放在aidl文件夹里面了
到这里先了解下,AIDL支持的数据类型:
基本数据类型(int, long, char, boolean, 等)
String和CharSequence
List 只支持ArrayList,里面的每个元素必须都能够被AIDL支持
Map 只支持HashMap,里面的每个元素都必须被AIDL支持,包括key和value
Parcelable 所有实现了Parcelable接口的对象
AIDL 所有的AIDL接口本身也可以在AIDL文件中使用
注意:
1.你必须显示import所有自定义的Parcelable对象,不管它们是否和当前AIDL文件在同一个包 内。
2.AIDL文件中用到的自定义的Parcelable类型,必须新建一个同名的AIDL文件
3.所有的非基本数据类型参数,必须标上方向:in(输入),out(输出)或者inout(输入输出)
把服务端aidl文件夹copy到client模块中
此时重新在Build->Rebuild Project下项目看下AIDL生成的Java类
生成的Java文件里面的内容还是有点复杂的,先不看了。
2.2)远程服务端的实现
定义好AIDL接口之后,接下来就需要在服务端实现这个接口
package com.chen.service.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import com.chen.service.IRemoteService;
public class RemoteService extends Service {
private IRemoteService.Stub mBinder = new IRemoteService.Stub(){
@Override
public int getPid() throws RemoteException {
return 123;
}
@Override
public String basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
return "我是服务端AIDL"+anInt+"-"+aLong+"-"+aBoolean+"-"+aFloat+"-"+aDouble+"-"+aString;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
<!--process:运行在独立进程中-->
<!--exported:是否支持其它应用调用当前组件。-->
<!--Android系统是否可以实例化应用的组件。如果为true可以,如果为
false不可以。如果为true时,每个组件的enabled属性决定了此组件
是否可用。如果为false,他重写了组件指定值,所有的组件将不还用。默认为true。-->
<service
android:name=".service.RemoteService"
android:enabled="true"
android:exported="true"
android:process=":remote"
></service>
2.3)客户端的实现
package com.chen.demo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import com.chen.service.IRemoteService;
public class MainActivity extends AppCompatActivity {
private IRemoteService mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent();
intent.setAction("android.chen.xiao.service");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
public void getPid(View view){
try {
int pid = mBinder.getPid();
Toast.makeText(this, "----->>>>>"+pid, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void basicTypes(View view){
try {
String result = mBinder.basicTypes(1, 2L, true, 10.3f, 11, "AIDL");
Toast.makeText(this, "----->>>>>"+result, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBinder = IRemoteService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
}
运行结果
我们可以看到此时客户端已经成功调用了远程服务端的方法,并打印出正确的值。
3) 传递一个自定义对象
当你想要在客户端和服务器之间传递一个对象时,你必须实现Parcelable接口,才能实现进程通信
为了创建一个自定义对象,你必须做以下几件事:
1)实现Parcelable接口
2 )实现writeToParcelable,保存当前状态并写入Parcel
3 ) 添加一个静态的实现了 Parcelable.Creator接口的字段
4 )创建一个和自定义对象同名的.aidl文件,
通常我们一般是用工具来序列化Parcelable,看图:
就是第一个,点击Install,重启as就可以使用,看下怎么用
这是生成的代码
package com.chen.service;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by chenxiaokang on 2016/12/1.
*/
public class Rect implements Parcelable{
public int left;
public int top;
public int right;
public int bottom;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.left);
dest.writeInt(this.top);
dest.writeInt(this.right);
dest.writeInt(this.bottom);
}
public Rect() {
}
protected Rect(Parcel in) {
this.left = in.readInt();
this.top = in.readInt();
this.right = in.readInt();
this.bottom = in.readInt();
}
public static final Creator<Rect> CREATOR = new Creator<Rect>() {
@Override
public Rect createFromParcel(Parcel source) {
return new Rect(source);
}
@Override
public Rect[] newArray(int size) {
return new Rect[size];
}
};
}
4 )最后
AIDL使用介绍差不多就这些了,服务的所有基本用法这三篇已经介绍得差不多了,其实这只是最基本的用法,很多深入的东西都没介绍,太菜了~~~~,以后nb了再深入总结。
5 ) 扩展学习
1)AIDL官方文档
2)http://www.open-open.com/lib/view/open1454895889776.html
3)http://blog.csdn.net/small_love/article/details/6534956
4)《Android开发艺术探索》IPC通信,这一章AIDL使用介绍的还是比较深入的,这里就不介绍了,同时其他IPC通信方式也值得学习,有时间总结下。