Android進程間通信機制——AIDL

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

這一步完成即完成了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/...路徑下查看。
查看生成的java代碼


二、創建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進行進程間通信就完成了。

博客地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章