AIDL
1. 什麼是AIDL
AIDL(Android Interface Definition Language,即Android接口定義語言。)
IPC(Inter-Process Communication,進程間通信)。
在進程間通信不一定需要AIDL,因爲兩個進程間不能直接通信,需要Android系統底層間接實現通信,所以比較耗資源,能不用就不用。如下圖:
進程間通訊可以分爲下面幾種:
AIDL
在IPC時,並且多個應用,多線程時纔用到。
Binder
只有IPC,多個應用,沒有多線程
Messager
只有IPC,沒有多線程
2. 創建AIDL
官方文檔上的例子:
// IRemoteService.aidl,//包名,文件必須放在指定的目錄
package com.example.android;
// Declare any non-default types here with import statements
/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
官方文檔上寫AIDL支持的數據類型包括:
- 所有的基本數據類型;
- String ,CharSequence
- List,Map
實際上基本數據類型的short類型不被支持,編譯都通不過。
還有Parcelable(序列化)。 - Parcelable(序列化)
那AIDL文件我們怎麼轉成java文件呢?在sdk\build-tools\23.0.2(版本)下有個aidl.exe文件,我們就是用這個來轉成java文件:
輸入命令:aidl IRemoteService.aidl
就會生成一個同名的java文件。
在eclipse中創建AIDL
新建一個Android項目後,直接在java文件中new一個aidl文件
在eclipse中自動編譯生成java,而java就和R文件在一起:
這樣就可以直接在Activity中提示出來了
在Android studio中創建AIDL
而Android studio中和eclipse有點不同,是和java同級目錄創建
編譯後生成的java文件:
3. 下面用一個案例
客戶端傳兩個數字,調用服務端的計算方法求和
首先服務端的AIDL文件代碼:
package com.hou.aidl;
interface IMyAidlInterface {
int add(int num1,int num2);
}
然後服務端需要遠程Service,代碼:
package com.hou.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class IRemoteService extends Service {
//當客戶端綁定服務時,會返回iBinder對象
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
private IBinder iBinder = new IMyAidlInterface.Stub() {
@Override
public int add(int num1, int num2) throws RemoteException {
Log.e("111", "收到了遠程傳過來的值" + num1 + "和" + num2);
return num1 + num2;
}
};
}
note:需要在清單文件中註冊,並添加intent-filter
<service android:name=".IRemoteService">
<intent-filter>
<action android:name="com.hou.aidl.client" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
客戶端:
package com.hou.aidlclient;
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.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.hou.aidl.IMyAidlInterface;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText et_num1;
private EditText et_num2;
private EditText et_sum;
private Button btn_sum;
private IMyAidlInterface iMyAidlInterface;
private ServiceConnection conn = new ServiceConnection() {
//服務綁定上的時候
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("111", "綁定服務成功==" + name);
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
//服務斷開的時候
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("111", "服務斷開連接==" + name);
iMyAidlInterface = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
bindAidlService();
}
private void initView() {
et_num1 = (EditText) findViewById(R.id.et_num1);
et_num2 = (EditText) findViewById(R.id.et_num2);
et_sum = (EditText) findViewById(R.id.et_sum);
btn_sum = (Button) findViewById(R.id.btn_sum);
btn_sum.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int num1 = Integer.parseInt(et_num1.getText().toString());
int num2 = Integer.parseInt(et_num2.getText().toString());
try {
int sum = iMyAidlInterface.add(num1, num2);
et_sum.setText(sum + "");
} catch (RemoteException e) {
et_sum.setText("出錯了");
e.printStackTrace();
}
}
//綁定服務
private void bindAidlService() {
Intent intent = new Intent();
//在Android5.0以後只能已顯示intent方式啓動 綁定服務
intent.setComponent(new ComponentName("com.hou.aidl", "com.hou.aidl.IRemoteService"));
// Intent intent = new Intent("com.hou.aidl.client");//隱式意圖方式
bindService(intent, conn, Context.BIND_AUTO_CREATE);//Context.BIND_AUTO_CREATE自動創建
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
現在就可以使用了,啓動服務端,打開客戶端就可以求和計算。
當然除過上邊提到的類型外,我們經常會傳遞自定義類型的數據,比如一個對象Person。
服務端:
創建一個Person對象,實現Parcelable序列化:
package com.hou.aidl;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by hp on 2016/3/9.
*/
public class Person implements Parcelable {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
protected Person(Parcel in) {
//必須和writeToParcel中寫入的順序一致;
name = in.readString();
age = in.readInt();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
創建Person.aidl
package com.hou.aidl;
parcelable Person;
package com.hou.aidl;
//需要引入Person
import com.hou.aidl.Person;
interface IMyAidlInterface {
List<Person> add(in Person person);
}
Service:
package com.hou.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
public class IRemoteService extends Service {
List<Person> persons;
//當客戶端綁定服務時,會返回iBinder對象
@Override
public IBinder onBind(Intent intent) {
persons = new ArrayList<>();
return iBinder;
}
private IBinder iBinder = new IMyAidlInterface.Stub() {
@Override
public List<Person> add(Person person) throws RemoteException {
persons.add(person);
return persons;
}
};
}
客戶端:
把IMyAidlInterface.aidl和Person.aidl都複製到客戶端同名包下(aidl-com.hou.aidl)
把Person複製到客戶端同名包下(com.hou.aidl)
package com.hou.aidlclient;
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.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.hou.aidl.IMyAidlInterface;
import com.hou.aidl.Person;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_sum;
private IMyAidlInterface iMyAidlInterface;
private ServiceConnection conn = new ServiceConnection() {
//服務綁定上的時候
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("111", "綁定服務成功==" + name);
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
//服務斷開的時候
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("111", "服務斷開連接==" + name);
iMyAidlInterface = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
bindAidlService();
}
private void initView() {
btn_sum = (Button) findViewById(R.id.btn_sum);
btn_sum.setOnClickListener(this);
}
@Override
public void onClick(View v) {
try {
List<Person> persons = iMyAidlInterface.add(new Person("李四", 18));
Person person = persons.get(0);
et_sum.setText(person.toString());
} catch (RemoteException e) {
et_sum.setText("出錯了");
e.printStackTrace();
}
}
//綁定服務
private void bindAidlService() {
Intent intent = new Intent();
//在Android5.0以後只能已顯示intent方式啓動 綁定服務
intent.setComponent(new ComponentName("com.hou.aidl", "com.hou.aidl.IRemoteService"));
// Intent intent = new Intent("com.hou.aidl.client");//隱式意圖方式
bindService(intent, conn, Context.BIND_AUTO_CREATE);//Context.BIND_AUTO_CREATE自動創建
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}