android中的AIDL学习笔记
一、定义
AIDL是用来解决进程间通信的(一般有四种方式:Activity、Service、ContentProvider、Broadcast Receiver),两个进程间无法直接通信,所以要用AIDL(属于前面提到的Service)来借助操作系统底层来间接进行通信,示意图如下:
AIDL全称为 Android Interface Definition Language,即Android接口定义语言。
二、AIDL开发(操作)流程
开发流程一般为:
1、定义AIDL文件(先在服务端定义,客户端也要定义,内容路服务端一样)
2、服务端实现接口
3、客户端调用接口
三、AIDL语法规则
语法规则如下:
1、语法跟Java的接口很相似
2、AIDL只支持方法,不能定义静态成员
3、AIDL运行方法有任何类型的参数(除short外)和返回值
4、除默认类型,均需要导包
四、AIDL支持的数据类型
1、除short外的基本数据类型
2、String, CharSequence
3、List(作为参数时,要指明是输入in 还是输出out), Map
4、Parcelable (自定义类型要实现 Parcelable 接口)
五、AIDL服务端与客户端之间的关系
六、AIDL适用场景
使用了IPC通信,多个客户端,多线程,否则可使用Binder或Messager
七、示例
1、在服务端定义自定义类型Person,实现 Parcelable 接口:
package com.atwal.aidl;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by Du on 2016/2/25.
*/
public class Person implements Parcelable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(Parcel source) {
this.name = source.readString();
this.age = source.readInt();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeInt(this.age);
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
return new Person(source);
}
@Override
public Person[] newArray(int size) {
return new Person[0];
}
};
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2、在服务端定义 Person.aidl :
// IImoocAidl.aidl
package com.atwal.aidl;
parcelable Person;
3、在服务端定义 IImoocAidl.aidl :
// IImoocAidl.aidl
package com.atwal.aidl;
import com.atwal.aidl.Person;
interface IImoocAidl {
//计算两个数的和
int add(int num1, int num2);
List<String> basicTypes(
byte aByte,
int aInt,
long aLong,
boolean aBoolean,
float aFloat,
double aDouble,
char aChar,
String aString,
in List<String> list);
List<Person> addPerson(in Person person);
}
4、在服务端定义Service(注意要在AndroidManifest.xml中定义):
package com.atwal.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Du on 2016/2/25.
*/
public class IRemoteService extends Service {
private ArrayList<Person> persons;
/**
* 当客户端绑定到该服务的时候,会执行
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
persons = new ArrayList<>();
return iBinder;
}
private IBinder iBinder = new IImoocAidl.Stub() {
@Override
public int add(int num1, int num2) throws RemoteException {
Log.d("TAG", "收到了远程的请求,输入的参数是 " + num1 + " 和 " + num2);
return num1 + num2;
}
@Override
public List<String> basicTypes(byte aByte, int aInt, long aLong, boolean aBoolean, float aFloat, double aDouble, char aChar, String aString, List<String> list) throws RemoteException {
return null;
}
@Override
public List<Person> addPerson(Person person) throws RemoteException {
persons.add(person);
return persons;
}
};
}
5、在客户端添加Person类,内容和包名都跟服务端一样
6、在客户端添加Person.aidl文件,内容和包名都跟服务端一样
7、在客户端添加IImoocAidl.aidl文件,内客和包名都跟服务端一样
8、客户端调用
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.atwal.aidlclient.MainActivity">
<EditText
android:id="@+id/et_num1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="num1"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="+"
android:textSize="20sp" />
<EditText
android:id="@+id/et_num2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="num2"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="="
android:textSize="20sp" />
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AIDL远程计算" />
</LinearLayout>
代码:
package com.atwal.aidlclient;
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.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.atwal.aidl.IImoocAidl;
import com.atwal.aidl.Person;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText mEtNum1, mEtNum2;
private TextView mTvResult;
private Button mBtnAdd;
private IImoocAidl iImoocAidl;
private ServiceConnection conn = new ServiceConnection() {
//绑定上服务的时候
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//拿到了远程的服务代理
iImoocAidl = IImoocAidl.Stub.asInterface(service);
}
//断开服务的时候
@Override
public void onServiceDisconnected(ComponentName name) {
//回收资源
iImoocAidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//应用一启动就绑定服务
bindSersvice();
}
private void initView() {
mEtNum1 = (EditText) findViewById(R.id.et_num1);
mEtNum2 = (EditText) findViewById(R.id.et_num2);
mTvResult = (TextView) findViewById(R.id.tv_result);
mBtnAdd = (Button) findViewById(R.id.btn_add);
mBtnAdd.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int num1 = Integer.parseInt(mEtNum1.getText().toString());
int num2 = Integer.parseInt(mEtNum2.getText().toString());
try {
//调用远程的服务
int res = iImoocAidl.add(num1, num2);
mTvResult.setText(String.valueOf(res));
} catch (RemoteException e) {
e.printStackTrace();
mTvResult.setText("错误了");
}
try {
List<Person> persons = iImoocAidl.addPerson(new Person("atwal", 21));
Log.d("TAG", persons.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void bindSersvice() {
//获取到服务端
Intent intent = new Intent();
//新版本(5.0以上)必须显示Intent启动绑定服务
intent.setComponent(new ComponentName("com.atwal.aidl", "com.atwal.aidl.IRemoteService"));
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
整个项目目录结构如下: