Android AIDL(一)

1.AIDL
2.AIDL支持的数据类型
3.定义传输数据以及数据的AIDL化
4.定义跨进程调用的接口的AIDL文件
5.生成与定义接口的aidl文件对应的Java类
6.编写Service并使用自动生成的Java类
7.配置Service属性
8.在Activity中进行IPC的示例

本文整理了Android AIDL的几个基本知识。

1.AIDL

AIDL(Android Interface Definition Language,Android接口定义语言),主要用来描述一组用于Android IPC的跨进程调用的接口,配合Service实现本地的RPC(远程过程调用),这样就可以在一个进程中像调用本进程内的对象的接口那样与另外一个进程进行通信。
AIDL的底层依赖于Binder,所以AIDL的使用又要涉及到Binder。
下面介绍AIDL的使用。

2.AIDL支持的数据类型

基本数据类型:byte、char、short、int、long、float、double
字符序列:String、CharSequence
Parcelable:实现了Parcelable接口的对象
AIDL:在AIDL文件中描述的接口或类
HashMap:元素必须能够被AIDL支持
ArrayList:元素必须能够被AIDL支持,包括key和value

3.定义传输数据以及数据的AIDL化

假如需要在AIDL中传输一个实现了Parcelable接口的Book对象,那么我们首先应该创建并实现该Book类。

package com.trb.androidlearn_1.ipc.aidl;

public class Book implements Parcelable {
    public int bookId;
    public String bookName;

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    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 String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", bookName='" + bookName + '\'' +
                '}';
    }
}

在该示例中,除了定义成员变量,其它的代码都可以利用Android Studio自动生成。

在定义好Book类后,我们需要对Book类AIDL化。对数据的AIDL化,就是创建一个同名的aidl文件,然后再该aidl文件中对Java类进行parcelable声明。
下面是对Book类的AIDL化的Book.aidl文件的示例:


// IBook.aidl
package com.trb.androidlearn_1.ipc.aidl;

// Declare any non-default types here with import statements
parcelable Book;

注意:
aidl文件和Java类文件的package的路径必须是一致的,在Android Studio中,Android Studio会自动在main目录下创建一个与java目录并列的aidl目录,然后在aidl目录下创建一个与Java类文件所在路径同名的包。但不要过分纠结这个问题。

4.定义跨进程调用的接口的AIDL文件

AIDL的目的是对外部进程提供一组调用接口,所以需要在aidl文件中定义这些接口。
例如我们创建了一个IBookManager.aidl文件,并在该文件中定义了一组接口。


// IBookManager.aidl
package com.trb.androidlearn_1.ipc.aidl;

import com.trb.androidlearn_1.ipc.aidl.Book;

// Declare any non-default types here with import statements

interface IBookManager {
    List<Book> getBookList();

    void addBook(in Book book);
}

注意:
IBookManager.aidl文件中import的是aidl目录下的Book.aidl文件。

5.生成与定义接口的aidl文件对应的Java类

该步骤既可以利用Android Studio自动生成,也可以手动编写。
在编写完定义接口的aidl文件,可以利用Build下的Make Project或Clean Project指令来自动生成对应的Java类文件,该文件位于“app\build\generated\source\aidl\debug”目录下的对应路径下。例如IBookManager.aidl对应的Java类的就位于“app\build\generated\source\aidl\debug\com\trb\androidlearn_1\ipc\aidl”目录下。

6.编写Service并使用自动生成的Java类

AIDL需要配合public IBinder Service.onBind(Intent intent)方法进行使用。


package com.trb.androidlearn_1.ipc.aidl;

public class BookManagerService extends Service {
    private static final String TAG = BookManagerService.class.getSimpleName();
    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();


    private Binder mBinder = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            Log.i(TAG, "getBookList: ");
            return mBookList;
        }
        @Override
        public void addBook(Book book) throws RemoteException {
            Log.i(TAG, "addBook: 2" + book.toString());
            book.bookId = mBookList.size() + 1;
            mBookList.add(book);
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

在onBind()方法中,我们需要返回自动生成的java类中Stub类的一个实例。

7.配置Service属性

<service
            android:name=".ipc.aidl.BookManagerService"
            android:process=":remote_aidl" />

android:process属性用来配置启用多进程。

8.在Activity中进行IPC的示例


package com.trb.androidlearn_1.ipc;

public class IpcActivity extends AppCompatActivity {
    private static final String TAG = IpcActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ipc);
        Log.d(TAG, "onCreate: pid = " + Process.myPid());

        Intent intent = new Intent(getApplication(), BookManagerService.class);
        bindService(intent, bookServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        unbindService(bookServiceConnection);
        super.onDestroy();
    }

    private IBookManager iBookManager;

    private ServiceConnection bookServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: ");
            iBookManager = IBookManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected: ");
            iBookManager = null;
        }
    };


    public void addBook_OnClick(View view) {
        if (iBookManager == null) return;

        EditText editText = findViewById(R.id.editText_1_IpcActivity);
        String bookName = editText.getText().toString().trim();

        if (TextUtils.isEmpty(bookName)) {
            return;
        }

        try {
            iBookManager.addBook(new Book(-1, bookName));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    public void getAllBooks_OnClick(View view) {
        if (iBookManager == null) return;

        try {
            List<Book> list = iBookManager.getBookList();
            for (Book book : list) {
                Log.d(TAG, "getAllBooks_OnClick: " + book.toString());
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

通过Context.bindService(Intent service, ServiceConnection conn, int flags)方法来绑定启动Service,在ServiceConnection的回调方法onServiceConnected(ComponentName name, IBinder service)中通过IBookManager.Stub.asInterface(service)方法将该对象转换成可以进行IPC的IBookManager的对象iBookManager,最后通过iBookManager对象中的方法调用就可以与处于com.trb.androidlearn_1:remote_aidl进程中的BookManagerService进行IPC。

猜你喜欢

转载自blog.csdn.net/yumeizui8923/article/details/80392880