Android_AIDL
1. AIDL (Android Interface DefinitionLanguage )接口描述语言
2. AIDL 适用于 进程间通信,并且与Service端多个线程并发的情况,如果只是单个线程 可以使用 Messenger ,如果不需要IPC 可以使用Binder
3. AIDL语法:基础数据类型都可以适用,List Map等有限适用。static field 不适用。
要使用AIDL我们需要两个应用程序,一个作为Service端,一个作为Client端。详细步骤如下:
基本使用步骤:
第一步:在Service端建立.aidl文件。实际实现的接口是在 gen中自动生成的对应的抽象内部类 Stub。注意:
1、导入包名,不能在src目录下创建,否则在实现的时候找到Stub类。
2、如果有使用Object对象,需要该对象 implement Parcelable 接口,并且需要导入该接口包名+类名,如果是primitivetype 不需要这步。
3、定义方法名称。
4、所有的.aidl文件以及需要传递的对象接口需要在Service 与Client中各一份,并且包名要和服务器端的一样(建议从服务器端拷贝)。
示例代码:
package com.example.android_aidl_host.aidl;
interface IRemoteService{
int getId();
void setId(int id);
}
第二步:在Service中实现.aidl 接口(通常在service中实现)。
public class MyHostService extends Service{
privateint id;
@Override
publicIBinder onBind(Intent intent) {
//TODO Auto-generated method stub
returnbind;
}
privatefinal IRemoteService.Stub bind = new IRemoteService.Stub() {
@Override
publicint getId() throws RemoteException {
//TODO Auto-generated method stub
returnid;
}
@Override
publicvoid setId(int id) throws RemoteException {
//TODO Auto-generated method stub
MyHostService.this.id= id;
}
};
}
注意:在服务器端建立好service要在manifest文件中进行注册,并且为其加上action属性。我的配置如下:
<serviceandroid:name="com.example.android_aidl_host.MyHostService">
<intent-filter>
//其它程序通过此入口获得数据,就好比ContentProvider
<actionandroid:name="com.xz.apk"/>
</intent-filter>
</service>
经过以上两步服务器的代码就已经完成了,就等其它进程来获取数据了。下面来写Client端的代码。
第一步:在Activity中通过Intent意图绑定service。
Intent service = new Intent("com.xz.apk");//必须与服务器端一致
bindService(service, new MyConn(),BIND_AUTO_CREATE);
第二步:获取服务返回的stub对象。
iService = IRemoteService.Stub.asInterface(service);
完整的Activity代码如下:
public class MainActivity extends Activity {
//aidl文件生成的java文件名
IRemoteService iService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定service
Intent service = new Intent("com.xz.apk");
bindService(service, new MyConn(),BIND_AUTO_CREATE);
}
public void changId(View view) {
switch (view.getId()) {
case R.id.set://客户端的set按钮
try {
//调用服务器端的setId()方法
iService.setId(200);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.get: //客户端的get按钮
try {
//调用服务器端的getId()方法
iService.getId();
Log.e("DDDDD",iService.getId() + "");
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
private class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service){
//通过自动生成的Stub内部类,调用asInterface()方法实例化IRemoteService对象
iService =IRemoteService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generatedmethod stub
}
}
}
Demo2:通过AIDL传递对象(Person),此实例既传递了普通数据又传递了对象。
1、定义该对象Person,并实现Parcelable。
2、添加Person.aidl文件,并采用如下方式编写导入Person
注意Person文件和Person.aidl文件必须放在同一个包中并且两者要同时存在,否则报错。
3、需要在引用到Person的.aidl文件中import+Person所在包名
4、需要在服务端和客户端都添加 Person.aidl与 Person.java文件并且需要一致。
Person类代码:
package com.example.android_aidl_mydemo_server.aidls;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
String name;
int age;
//省略了相应的get和set方法
/**
* 在想要进行序列号传递的实体类内部一定要声明该常量。常量名只能是CREATOR,类型也必须是
* Parcelable.Creator<T>
*/
public static final Parcelable.Creator<Person>CREATOR = newParcelable.Creator<Person>() {
/***
* 根据序列号的Parcel对象,反序列号为原本的实体对象
* 读出顺序要和writeToParcel的写入顺序相同
*/
public Person createFromParcel(Parcel in) {
// String name =source.readString();
// int age =source.readInt();
// String sex =source.readString();
// Beauty beauty =new Beauty();
// beauty.setName(name);
// beauty.setAge(age);
// beauty.setSex(sex);
//
// returnbeauty;
return new Person(in);
}
/**
* 创建一个要序列号的实体类的数组,数组中存储的都设置为null
*/
public Person[] newArray(int size) {
return new Person[size];
}
};
public Person() { }
private Person(Parcel in) {
readFromParcel(in);
}
public int describeContents() {
return 0;
}
public void readFromParcel(Parcel in) {
age = in.readInt();
name = in.readString();
}
/**
* 将对象序列号dest 就是对象即将写入的目的对象 flags有关对象序列号的方式的标识
* 这里要注意,写入的顺序要和在createFromParcel方法中读出的顺序完全相同。例如这里先
*写入的为name,
* 那么在createFromParcel就要先读name
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
}
}
Person.aidl文件:
packagecom.example.android_aidl_mydemo_server.aidls;
parcelable Person;
InData.aidl文件:
packagecom.example.android_aidl_mydemo_server.aidls;
import com.example.android_aidl_mydemo_server.aidls.Person;
interface InData{
String getName();
void setName(String name);
Person getPerson();
}
服务器端的service文件:
package com.example.android_aidl_mydemo_server;
import com.example.android_aidl_mydemo_server.aidls.InData;
import com.example.android_aidl_mydemo_server.aidls.Person;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyServer extends Service {
String name = "JACK";
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generatedmethod stub
returnbinder;
}
private final InData.Stub binder = new InData.Stub() {
@Override
public String getName()throws RemoteException {
// TODO Auto-generatedmethod stub
returnname;
}
@Override
public void setName(String name) throws RemoteException {
// TODO Auto-generatedmethod stub
MyServer.this.name = name;
}
@Override
publicPersongetPerson() throws RemoteException {
// TODO Auto-generatedmethod stub
Person person = new Person();
return person;
}
};
}
一说到service我又想起了一定不要忘记在manifest注册并加上action属性!
客户端MainActivity的代码:
package com.example.android_aidl_mydemo_client;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import com.example.android_aidl_mydemo_server.aidls.InData;
import com.example.android_aidl_mydemo_server.aidls.Person;
public class MainActivity extends Activity {
InData inData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intentservice=newIntent("com.ssss.xz.apk");
bindService(service, new MyConnection(),BIND_AUTO_CREATE);
}
private class MyConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service){
// TODO Auto-generatedmethod stub
inData=InData.Stub.asInterface(service);
try {
Log.e("SSSSSS",inData.getName());
inData.setName("Hello AIDL");
Log.e("SSSSSS",inData.getName());
Person user=inData.getPerson();
Log.e("HHHHHHHH",user.getName());
Log.e("HHHHHHHH",user.getAge()+"");
} catch (RemoteException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generatedmethod stub
inData=null;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; thisadds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
在写这篇文章之前,看了相关的官方文档,在网上也查了相应的资料。当时有一篇文章写的很详细,但是现在忘记地址了,所以这篇文章可能会和大神写的有点类似,在此说声抱歉。但我保证两个Demo都是自己写的。OK,关于aidl我所知道的一切都已经说了。剩余的交给童鞋们了。
源码就不加了,上面都写的差不多了。