Android關于aidl的理解

原創博客地址

AIDL簡介

Android中,進程之間原則上是不能進行通信的。但偏偏Android從四大組件到框架、底層到處都是IPC的影子。AIDL就是IPC方式之一。

AIDLAndroid 接口定義語言) 是 Android 提供的一種進程間通信 (IPC) 機制。

我們可以使用它在兩個不同進程之間ClientServer進行通信

使用AIDL步驟

使用aidl大致分為三塊,編寫aidl生成必要文件。創建ClientServer使用。

  • 編寫AIDL
    • 創建Bean類,實現Parcelable接口(便于序列化反序列化)。
    • 編寫aidl文件
    • 生成java文件
  • 編寫Server
    • 創建 Service,在其中創建上面生成的 Binder 對象實例,實現接口定義的方法
    • onBind()中返回
  • 編寫Client
    • 實現 ServiceConnection 接口,在其中拿到 AIDL
    • 綁定服務
    • 調用aidl中的請求并等待返回結果

步驟一:編寫AIDL

  • 創建Bean類,實現Parcelable接口(便于序列化反序列化
package com.cx.aidldemo.bean;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * 書的實體類
 */
public class Book implements Parcelable {

    private String name;
    private double price;

    public Book() {}

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    protected Book(Parcel in) {
        name = in.readString();
        price = in.readDouble();
    }

    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(name);
        dest.writeDouble(price);
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
  • 編寫aidl文件

    • 不過在編寫aidl文件之前,要擁有aidl目錄。沒有的話就創建。
    • 創建方式:在main目錄下創建aidl目錄,并在aidl目錄下創建和java目錄下子目錄一樣的包名。
aidl包名一致.png
  • 創建Bean類的aidl
// Book.aidl
package com.cx.aidldemo.bean;

parcelable Book;
  • 創建接口的aidl
// IMyService.aidl
package com.cx.aidldemo;

import com.cx.aidldemo.bean.Book;

interface IMyService {

    /**
     * 添加一個書
     */
    void addBook(in Book book);

    /**
     * 獲取所有書
     */
    List<Book> getBookList();
}

?

注意:

  1. 這個 Book.aidl 的包名要和實體類包名一致。
  2. 除了基本數據類型,其他類型的參數都需要標上方向類型:in(輸入),out(輸出),inout(輸入輸出)。
  3. 非基本類型的數據需要導入它的全路徑。即便是同級目錄下。
  • 生成java文件
    • 方式:Build -> Make Project
    • 然后就會在app/build/generated/source/aidl/package_name/ 下生成一個 Java 文件
生成java文件.png

現在我們就可以通過它來進行IPC通信了。

步驟二:編寫Server

  • 創建 Service,在其中創建上面生成的 Binder 對象實例,實現接口定義的方法
  • onBind()中返回
public class MyAIDLService extends Service {

    private List<Book> books;

    public MyAIDLService() {
    }

    private IBinder mIBinder = new IMyService.Stub() {
        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            return books;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        books = new ArrayList<Book>();
        return mIBinder;
    }
}   

配置清單:

<service
    android:name=".MyAIDLService"
    android:enabled="true"
    android:exported="true"
    android:process=":aidl"></service>
  • enabled屬性
    • 默認為true
    • 其值為true,則說明應用程序組件可以被Android系統自動實例化
    • 如果為false,則說明實例化組件的工作需要手工完成。
  • exported屬性
    • 是否支持其它應用調用當前組件
    • 如果包含有intent-filter 默認值為true;沒有intent-filter默認值為false
  • process屬性
    • 如果該屬性里設置的名字以冒號開頭(:),那么在需要的時候它將生成該應用程序的一個私有新進程

服務端實現了接口,在 onBind() 中返回這個 Binder,客戶端拿到就可以操作數據了。

步驟三:編寫Client

  • 實現 ServiceConnection 接口,在其中拿到 AIDL
public class MainActivity extends AppCompatActivity {

    private IMyService iMyService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // onBind連接后會返回 Binder,也就是iBinder參數
            // 將其轉換成 AIDL,在不同進程會返回代理對象
            iMyService = IMyService.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            iMyService = null;
        }
    };
}
  • 綁定服務
Intent intent1 = new Intent(getApplicationContext(), MyAIDLService.class);
// 綁定服務
bindService(intent1, connection, BIND_AUTO_CREATE);
  • 調用aidl中的請求并等待返回結果
/**
 * 添加一本書
 * @param view
 */
public void onAddBook(View view) {
    Book book = new Book("Android_" + System.currentTimeMillis(), 100);
    try {
        iMyService.addBook(book);
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

/**
 * 獲取所有書籍
 * @param view
 */
public void onGetBooks(View view) {
    try {
        tvResult.setText(iMyService.getBookList().toString());
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

日志打印:

服務端進程名.png

客戶端進程名.png

運行結果:

運行結果.gif

源碼Demo下載地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容