通過使用AIDL在兩個(gè)應(yīng)用間實(shí)現(xiàn)通信
一、創(chuàng)建 service 端
新建一個(gè) service project 在對應(yīng)路徑下右鍵 -> new -> AIDL -> AIDL File 系統(tǒng)會幫我們自動生成 AIDL 路徑和對應(yīng)的 AIDL 文件

生成完成后對應(yīng)的目錄如下:

編寫 IUserCalcAIDL.aidl 文件
//這里只是簡單的獲取用戶名和密碼
interface IUserCalcAIDL {
String getUserName();
String getPassWord();
}
在 java 目錄下新建一個(gè) service
public class UserService extends Service {
//如果此時(shí)沒有這個(gè)類,重新構(gòu)建一下項(xiàng)目
private final IUserCalcAIDL.Stub mBind = new IUserCalcAIDL.Stub() {
@Override
public String getUserName() throws RemoteException {
return "mao_kk";
}
@Override
public String getPassWord() throws RemoteException {
return "1234567890";
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBind;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
繼續(xù)在 AndroidManifest.xml 中配置 service
<service
android:name=".UserService"
//設(shè)置外部可以訪問
android:enabled="true"
android:exported="true">
<intent-filter>
//配置 action 5.0以后不能使用隱式方式訪問,所以要設(shè)置
<action android:name="com.androidtv.aidlservice.AIDLService" />
</intent-filter>
</service>
到這里 service 端的配置完成,此時(shí)的目錄結(jié)構(gòu)為:

運(yùn)行該項(xiàng)目,等待
二、創(chuàng)建 client 端
新建一個(gè) client project 在對應(yīng)的路徑下將 service 端下的 aidl 文件夾拷貝過來,此時(shí)項(xiàng)目結(jié)構(gòu)為:

注意,如果手動編寫 aidl 文件夾,需要包名和 service 端的相對應(yīng),下面來編寫 MainActivity ,MainActivity中只有幾個(gè)按鈕,bindService 、獲取用戶名、獲取密碼,布局簡單,就不貼 xml 代碼了
private IUserCalcAIDL mIUserCalcAIDL;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("TAG", "onServiceConnected: ---->");
mIUserCalcAIDL = IUserCalcAIDL.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("TAG", "onServiceDisconnected: ----->");
mIUserCalcAIDL = null;
}
};
private void bindAIDLService() {
//5.0 之后不能隱式啟動
Intent intent = new Intent();
intent.setAction("com.androidtv.aidlservice.AIDLService");
intent.setPackage("com.androidtv.aidlservice");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private void getPassWord() {
if (mIUserCalcAIDL != null) {
try {
//獲取密碼 這里得到的就是 1234567890
String passWord = mIUserCalcAIDL.getPassWord();
Toast.makeText(this, passWord, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服務(wù)未連接", Toast.LENGTH_SHORT).show();
}
}
private void getUserName() {
if (mIUserCalcAIDL != null) {
try {
//獲取用戶名 這里的到的就是 mao_kk
String passWord = mIUserCalcAIDL.getUserName();
Toast.makeText(this, passWord, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服務(wù)未連接", Toast.LENGTH_SHORT).show();
}
}
到這里,一個(gè)簡單的 AIDL 就結(jié)束了,需要注意的是,如果需要使用自定義的數(shù)據(jù)類型需要進(jìn)行配置
三、自定義數(shù)據(jù)類型
在 service 端中 java 目錄下新增需要的自定義類型,注意:該類型是需要實(shí)現(xiàn) Parcelable 接口
//自定義 Book 類型,里面包含一個(gè) bookName 字段
public class Book implements Parcelable {
private String bookName;
protected Book() {
}
protected Book(Parcel in) {
bookName = in.readString();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookName);
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
}
在 aidl 目錄下新增 Book.aidl 文件,定義自定義類型
// IUserCalcAIDL.aidl
package com.androidtv.aidlservice;
// 定義 Book
parcelable Book;
重新編寫 IUserCalcAIDL.aidl 文件
package com.androidtv.aidlservice;
// import 導(dǎo)入自定義類型
import com.androidtv.aidlservice.Book;
interface IUserCalcAIDL {
String getUserName();
String getPassWord();
//獲取 books 列表
List<Book> getBooks();
//往 books 列表中增加數(shù)據(jù)
//注意 需要在類型前加 in
void addBook(in Book book);
}
重新編譯項(xiàng)目,修改 UserService 內(nèi)容
public class UserService extends Service {
List<Book> mBookList = new ArrayList<>();
//多了兩個(gè)實(shí)現(xiàn)方法
private final IUserCalcAIDL.Stub mBind = new IUserCalcAIDL.Stub() {
@Override
public String getUserName() throws RemoteException {
return "mao_kk";
}
@Override
public String getPassWord() throws RemoteException {
return "1234567890";
}
@Override
public List<Book> getBooks() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
@Override
public void onCreate() {
super.onCreate();
//默認(rèn)增加一個(gè)book
Book book = new Book();
book.setBookName("語文");
mBookList.add(book);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBind;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
此時(shí) service 端的結(jié)構(gòu)為

service 端的修改完成,接下來修改 client 端,將 service 端下的aidl 文件夾重新拷貝一份到 client 端 中,同時(shí)將自定義的數(shù)據(jù)類型也拷貝過去,注意:自定義類型的包名需要和 service 端的相對應(yīng),完成后 client 端的項(xiàng)目結(jié)構(gòu)為:

在 MainActivity 中可以有對應(yīng)操作代碼
private void addBookList() {
if (mIUserCalcAIDL != null) {
try {
Book book = new Book();
book.setBookName("數(shù)學(xué)");
mIUserCalcAIDL.addBook(book);
List<Book> books = mIUserCalcAIDL.getBooks();
for (Book book1 : books) {
Log.e("TAG", "addBookList: --->" + book1.getBookName());
}
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服務(wù)未連接", Toast.LENGTH_SHORT).show();
}
}
private void getBookList() {
if (mIUserCalcAIDL != null) {
try {
List<Book> books = mIUserCalcAIDL.getBooks();
for (Book book : books) {
Log.e("TAG", "getBookList: ----->" + book.getBookName());
}
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服務(wù)未連接", Toast.LENGTH_SHORT).show();
}
}
到此結(jié)束