美文网首页程序员
快速掌握aidl

快速掌握aidl

作者: sys_out | 来源:发表于2019-01-03 22:46 被阅读4次

aidl是Android中用于跨进程通讯的语言。当需要在项目中使用多个进程,可以使用此技术实现进程间通信。那么如何使用aidl呢?

1. 创建aidl文件

在src/main目录下面右键创建aidl文件,androidStudio会给我们自动生成相应的目录和示例文件。

自动生成的目录和文件
2. 创建需要的传输的实体类bean

需要知道 : aidl中支持java的8中基础数据类型和Charsequence、String、List、Map。引用对象类型需要序列化,且仅支持parcelable方式的序列化。

public class Book implements Parcelable {

    private String name;
    private float price;

    public Book(Parcel in) {
        this.name = in.readString();
        this.price = in.readFloat();
    }

    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.writeFloat(price);
    }
}
3. 创建声明实体类的aidl文件

第二点说了aidl只支持固定的几种数据类型,对于引用类型,如果想支持的话,需要创建对应的xxx.aidl的文件,然后在里面声明该实体类。一个aidl文件对应一个实体类。必须这样,才能正常编译运行程序。比如在Book.aidl文件中声明Book对象
需要知道:aidl文件中,如果要访问其他文件对象,需要import 该文件包名。即使他们在同一个包下(这个和kotlin、dart语言类似,一个文件相当于包的访问权限)

// Book.aidl
package com.example.bangbangqiu.bluetoothapp;

// Declare any non-default types here with import statements
import com.example.bangbangqiu.bluetoothapp.Book;
parcelable Book;
4. 修改IMyAidlInterface.aidl文件

这个文件也是最关键的文件。在这个接口文件中声明方法,它作为服务进程与客户端进程之间的桥梁。

声明的方法和接口方法声明一样 只需要 返回类型 + 方法名的格式。
会看到 参数中有带关键字in(定向tag)。在aidl中方法参数 可以用 in out inout修饰,in表示数据由客户端流向服务器端,out反之,inout数据双向都可传输。

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    List<Book> getBooks();
    void addBook(in Book book);
    void feedBack();
}

到此aidl部分已经完成了,编译之后,会在build/generate/source/aidl文件下面看到ide自动生成的aidl的实现类。下面就需要写客户端和服务端的代码逻辑了

5. 创建服务进程

创建service并使其在名为remote的进程中运行

public class AIDLService extends Service {

    List<Book> books = new ArrayList<>();

    IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() {
        @Override
        public List<Book> getBooks() throws RemoteException {
            return books;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }

        @Override
        public void feedBack() throws RemoteException {
            Log.d("AIDLService", "feedBack: is running");
        }

    };

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

    public IBinder mBinder = new MyBinder();

    public class MyBinder extends Binder {
        public void feedBack() {
            Log.d("AIDLService", "feedBack: is running");
        }
    }
}

AndroidManifest.xml:

<service android:name=".AIDLService"
            android:process=".remote"
            android:exported="true">
            <intent-filter>
                <action android:name="com.bluetoothapp.aidl"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

如果熟悉service的bind方式,就会觉得上面代码其实和写个普通service没啥区别。只是返回的对象就是AIDL中创建的对象。

6. 写客户端逻辑

在客户端bindService即可,就是普通的bindservice写法。

 if (serviceConnection == null) {
            serviceConnection = new ServiceConnection() {


                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
                    Toast.makeText(SecondActivity.this, "onservice_connect", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {

                }
            };
            Intent intent = new Intent();
            intent.setAction("com.bluetoothapp.aidl");
            intent.setClass(this, AIDLService.class);
            bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
        }

编译可能会报错,如下


image.png

因为gradle构建的时候只会把src/main/java目录作为java代码目录,所以要加上

sourceSets {
        main {
            java.srcDirs = ['/src/main/java', 'src/main/aidl']
        }
    }

注意:bindService可能会发现报错,因为在android 5.0后强制要显式启动service 。
当前示例是在同个项目,在不同项目需要将aidl的目录拷贝一份
最后想说:写的比较浅显,主要是自我梳理和帮助没使用过的快速了解。

相关文章

网友评论

    本文标题:快速掌握aidl

    本文链接:https://www.haomeiwen.com/subject/fzoqrqtx.html