AIDL,通俗來說就是兩個Android應用要進行通信,且不能通過網絡雲服務器的方式進行數據交互,只能調用本地函數庫的機制來實現,這時Android系統提供AIDL的機制來實現Android的跨進程通訊(用戶進程之間是相對封閉的,無法直接訪問數據)。
我們先不管任何原理,把demo跑出來再說其他的:
準備材料:一個Service、一個Client、連接S—C的橋樑(AIDL文件)
第一步: 連接S—C的橋樑(AIDL文件),這個aidl文件是客戶端和服務器端都需要的,在服務端或者客戶端的項目中生成都可以,如果傳遞基本數據類型就直接使用,如果是引用數據類型,先聲明這個實體類,項目包結構如下
①Person類中主要是實現Parcelable接口,代碼如下
package com.testaidl.model;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by Administrator on 2018\10\31 0031.
*/
public class Person implements Parcelable {
private String name;
protected Person(Parcel in) {
name = in.readString();
}
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];
}
};
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
@Override
public String toString() {
return "Person{" +
"mName='" + this.getName() + '\'' +
'}';
}
}
②然後再項目的main結構下創建aidl文件夾,創建Person的aidl後綴文件,必須要和上面Person的包名(結構)相同,這個Person類很簡單就是聲明一下parcelable 接口,
③IMyAidl這個接口的方法是提供給C-S調用的,
// IMyAidl.aidl
package com.testaidl;
// 這個引用類型必須是全類名的才能使用
import com.testaidl.model.Person;
interface IMyAidl {
/**
* 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);
void addPerson(in Person person);
List<Person> getPersonList();
}
這樣子,AIDL這個中間件就做好了,把它分別放到代表:客戶端和服務器項目中(例如我們在客戶端的項目中生成AIDL文件,然後copy給服務器,但是要注意包名必須完全一致,C-S兩端都要一致的,有點童鞋會說我想將客戶端或者服務端放到之前的項目中,這時包名是定好的,不方便修改怎麼辦,在與當前包名同級的地方創建Person類,這樣就保證了C-S兩端包名都是一致的)
第二部:創建服務端,在新的項目中copyAIDL文件(放到項目中main結構的aidl文件夾中),一定要注意包名相同!!!,然後在完全相同的包結構下複製Person這個實體類,編譯一下程序,服務端其實就是Android四大組件中的Service,
package com.my_project.test_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 com.testaidl.IMyAidl;
import com.testaidl.model.Person;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2018\10\31 0031.
* 服務端 service
*/
public class MyAidlService extends Service {
private final String TAG = this.getClass().getSimpleName();
public ArrayList<Person> mPersons;
/**
* 創建生成的本地 Binder 對象,實現 AIDL 制定的方法
*/
private IBinder mIBinder = new IMyAidl.Stub() {
@Override
public void addPerson(Person person) throws RemoteException {
Log.e("11111111111",person.toString());
mPersons.add(person);
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Person> getPersonList() throws RemoteException {
return mPersons;
}
};
/**
* 客戶端與服務端綁定時的回調,返回 mIBinder 後客戶端就可以通過它遠程調用服務端的方法,即實現了通訊
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
mPersons = new ArrayList<>();
Log.e(TAG, "MyAidlService onBind");
return mIBinder;
}
}
然後咱們再清單文件中聲明service的時候要設置其action(這個名字可以隨意取的):
第三步:創建客戶端項目:同樣的方式copyAIDL文件和Person實體類,這個是和服務端一樣的,然後編譯生成Stub,做好準備工作以後,在客戶端上綁定這個服務,bingService(…)
package com.testaidl;
import android.content.ComponentName;
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.Button;
import android.widget.TextView;
import com.testaidl.model.Person;
import java.util.List;
import java.util.Random;
/**
* 客戶端client 代碼
* */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent1 = new Intent();
intent1.setPackage("com.my_project");
intent1.setAction("com.test_aidl.aidl");
bindService(intent1, mConnection, BIND_AUTO_CREATE);
final Button btn_test = findViewById(R.id.btn_test);
final TextView tv_test = findViewById(R.id.tv_test);
btn_test.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Random random = new Random();
Person person = new Person("shixin" + random.nextInt(10));
try {
mAidl.addPerson(person);
List<Person> personList = mAidl.getPersonList();
tv_test.setText(personList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private IMyAidl mAidl;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//連接後拿到 Binder,轉換成 AIDL,在不同進程會返回個代理
mAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mAidl = null;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
這樣客戶端生成好了,可以通過客戶端發消息給服務端,親測服務端可以收到消息