Android進程間通信機制之AIDL
AIDL的全稱爲:Android Interface Definition Language,即安卓接口定義語言。我們可以使用它定義客戶端和服務端通信時都認可的編程接口。
在Android中如果我們自己編寫這個過程的代碼,無疑是極其繁瑣的。因此我們可以利用AIDL來處理,我們只需要編寫aidl接口文件,然後再重新編譯一下項目系統會幫我們生產Binder接口。
在Android Studio中編寫AIDL
利用AIDL進行進程間通信的步驟如下:
-
創建AIDL文件
創建實體對象,實現Parcelable接口;
創建aidl文件夾,創建aidl接口文件和實體類的映射aidl文件(aidl文件包名路徑需要和實體對象包名路徑一致);
重新build一下項目。
-
實現Server端
創建service,創建Binder對象,實現接口方法;
在onBind中返回創建的Binder對象。
-
實現Client端
創建ServiceConnection對象,實現其方法,需要再其方法中拿到AIDL對象;
綁定服務bindService();
通過調用AIDL類中的方法向服務端發起請求。
一、創建AIDL文件
1.創建Book實體類,實現Parcelable接口;
package com.kanlulu.aidl_test.bean;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by kanlulu
*/
public class Book implements Parcelable {
private int bookId;
private String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
'}';
}
protected Book(Parcel in) {
bookId = in.readInt();
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.writeInt(bookId);
dest.writeString(bookName);
}
}
2.創建aidl文件夾和aidl文件
在和src/main目錄下創建aidl文件夾,需要保持和java文件夾在同一目錄下。在Android Studio中我們自然不需要一步一步手動創建aidl文件夾和aidl文件。如圖所示:
這一步完成即完成了aidl接口文件的創建,我們可以根據自己的需要寫一些接口方法:
// IBookManager.aidl
package com.kanlulu.aidl_test;
// Declare any non-default types here with import statements
import com.kanlulu.aidl_test.bean.Book;
interface IBookManager {
void addBook(in Book book);
List<Book> getBookList();
}
需要注意的是:
還要import我們用到的實體類import com.kanlulu.aidl_test.bean.Book; 因爲Book不是aidl支持的數據類型(aidl語法支持的數據類型:java的基本數據類型、List和Map、其他AIDL接口和實現Parcelable的實體類)。
void addBook(in Book book);
中的"in" 表示輸入,還有其他的:out表示輸出,inout表示輸入輸出。
接下來我們要創建實體類的映射adil文件,路徑需要與實體類保持一致,同時需要使用parcelable聲明我們的實體類對象;
// Book.aidl
package com.kanlulu.aidl_test.bean;
// Declare any non-default types here with import statements
parcelable Book;
最後我們只需要Make Project,系統就會幫我們自動生成Binder的java文件。我們可以再build/generated/source/aidl/...
路徑下查看。
二、創建Server
創建Service類,在類中創建Binder對象並實現接口方法,然後在onBind()總返回我們的Binder對象。
package com.kanlulu.aidl_test.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.kanlulu.aidl_test.IBookManager;
import com.kanlulu.aidl_test.bean.Book;
import java.util.ArrayList;
import java.util.List;
public class MyAIDLService extends Service {
private final String TAG = "MyAIDLService";
private ArrayList<Book> mBooks;
/**
* 根據我們的aidl創建Binder對象
*/
private IBinder mIBinder = new IBookManager.Stub() {
/**
*
* @param book 客戶端傳遞過來的數據
* @throws RemoteException
*/
@Override
public void addBook(Book book) throws RemoteException {
mBooks.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
return mBooks;
}
};
/**
* 返回我們創建的Binder對象
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "====== MyAIDLService onBind ======");
mBooks = new ArrayList<>();
return mIBinder;
}
}
不要忘了在AndroidManifest.xml文件中註冊Service組件
<service
android:name=".service.MyAIDLService"
android:enabled="true"
android:exported="true"
android:process=":aidl_test" />
三、創建Client進行通信
創建ServiceConnection對象,實現接口方法並拿到Binder對象然後轉換成AIDL。通過bindService()建立連接,之後就可以進行對Server端的訪問。
package com.kanlulu.aidl_test.client;
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.util.Log;
import android.view.View;
import android.widget.TextView;
import com.kanlulu.aidl_test.IBookManager;
import com.kanlulu.aidl_test.R;
import com.kanlulu.aidl_test.bean.Book;
import com.kanlulu.aidl_test.service.MyAIDLService;
import java.util.List;
/**
* AIDL:Android接口定義語言(Android Interface definition Language),是Android中的進程間通信機制。
* 在Android中一個進程是無法訪問另一個進程的內存,但是如果我們能夠將對象分解成操作系統能夠識別的原語,並將對象編組成跨越邊界的對象,
* 就能夠實現進程間的通信。
* Binder繼承自IBinder接口(IBinder接口代表了跨進程傳輸的能力);
*
*
*/
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private IBookManager mAidl;
private ServiceConnection aidlServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//連接後拿到 Binder,轉換成 AIDL,在不同進程會返回個代理
mAidl = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mAidl = null;
}
};
public TextView tvBooks;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startAIDLService();
tvBooks = (TextView) findViewById(R.id.tv_books);
}
private void startAIDLService() {
Intent intent = new Intent(this, MyAIDLService.class);
bindService(intent, aidlServiceConnection, BIND_AUTO_CREATE);
}
public void btnAdd(View view) {
Book bookName = new Book(10, "bookName");
try {
mAidl.addBook(bookName);
List<Book> bookList = mAidl.getBookList();
tvBooks.setText(bookList.toString());
} catch (RemoteException e) {
Log.e(TAG,e.getMessage());
}finally {
Log.d(TAG,"添加一本書...");
}
}
}
至此,在Android中利用AIDL進行進程間通信就完成了。