AIDL最佳实践

参考:Android 接口定义语言 (AIDL)

之前在Eclipse中进行过AIDL的实践,昨天又尝试着在AndroidStudio中实践,看了一些博客,感觉很多步骤还是没说清楚,耽误了一些时间。下面就整理一下关于AIDL实践的详细过程。

1.创建工程

工程名字叫AIDL_practice,有两个可以运行的module,client和server。顾名思义,client就是AIDL实践中的客户端,server是服务端。
这里写图片描述

2.初始化server

在server的src/main目录下创建AIDL文件,IMyAidl.aidl:
这里写图片描述

并且在其中添加一个add方法:
这里写图片描述

然后build一下server这个module,发现IDE为我们生成了一个名叫IMyAidl的Java文件:
这里写图片描述

这个时候我们就可以新建Service了:
这里写图片描述

最后别忘记在AndroidManifest.xml文件中声明Service的权限:

        <service
            android:name=".RemoteService"
            android:enabled="true"
            android:exported="true"/>

3.初始化client

然后我们把之前自己写的AIDL文件,IMyAidl.aidl,copy到client的同名目录下
这里写图片描述

再build一下client这个module,IDE同样为我们生成了一个名叫IMyAidl的Java文件,然后我们就开始写客户端逻辑了:

public class ClientActivity extends AppCompatActivity {
    private IMyAidl iMyAidl;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidl = IMyAidl.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMyAidl = null;
        }
    };

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

    private void initView() {
        final EditText num1Edt = (EditText) findViewById(R.id.num1);
        final EditText num2Edt = (EditText) findViewById(R.id.num2);
        Button addBtn = (Button) findViewById(R.id.add);
        final TextView resultTv = (TextView) findViewById(R.id.result);

        addBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String num1 = num1Edt.getText().toString().trim();
                String num2 = num2Edt.getText().toString().trim();
                if (TextUtils.isEmpty(num1)) {
                    Toast.makeText(ClientActivity.this, "请输入第一个数字", Toast.LENGTH_LONG).show();
                } else if (TextUtils.isEmpty(num2)) {
                    Toast.makeText(ClientActivity.this, "请输入第二个数字", Toast.LENGTH_LONG).show();
                } else {
                    if (iMyAidl != null) {
                        try {
                            int result = iMyAidl.add(Integer.valueOf(num1), Integer.valueOf(num2));
                            resultTv.setText(result + "");
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

    private void bindService() {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.aidl.tsnt.server", "com.aidl.tsnt.server.RemoteService"));
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

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

对应的layout,activity_client.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_client"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".ClientActivity">

    <EditText
        android:id="@+id/num1"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:hint="num1" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+" />

    <EditText
        android:id="@+id/num2"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:hint="num2" />

    <Button
        android:id="@+id/add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="=" />

    <TextView
        android:id="@+id/result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:textColor="@android:color/holo_red_dark" />
</LinearLayout>

然后我们把server和client都运行起来,client调用远程server端的RemoteService就可以进行加法运算了:
这里写图片描述

这里写图片描述

4.传递自定义数据类型

AIDL支持Java的基本数据类型,还有String,CharSequence,List,Map和实现了Parcelable的自定义数据类型。当然这里所指的List和Map中的元素也必须是支持AIDL的数据类型。
下面就介绍一下在AIDL中如何传递自定义数据类型。

在sever中新建一个Dog类:

public class Dog implements Parcelable {
    int age;

    public Dog(int age) {
        this.age = age;
    }

    protected Dog(Parcel in) {
        age = in.readInt();
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static final Creator<Dog> CREATOR = new Creator<Dog>() {
        @Override
        public Dog createFromParcel(Parcel in) {
            return new Dog(in);
        }

        @Override
        public Dog[] newArray(int size) {
            return new Dog[size];
        }
    };

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

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

再新建一个aidl配置文件,文件名必须使用Dog,否则系统编译无法找到或者识别Dog。但是得注意到这里如果直接创建的话,会遇到一个错误提示:
Interface Name must be unique
这里写图片描述

需要我们先新建一个其他名字的xx.aidl,再将xx.aidl重命名为Dog.aidl,内容如下:

// Dog.aidl
package com.aidl.tsnt.server;

parcelable Dog;

然后修改IMyAidl.aidl:

// IMyAidl.aidl
package com.aidl.tsnt.server;

import com.aidl.tsnt.server.Dog;//导包不要忘记

interface IMyAidl {
   int add(int num1,int num2);


   List<Dog> addDog(in Dog dog);//这里的in注意不要少
}

然后重新build,修改RemoteService的内容:

public class RemoteService extends Service {
    private List<Dog> mDogs = new ArrayList<>();

    Binder mBinder = new IMyAidl.Stub() {

        @Override
        public int add(int num1, int num2) throws RemoteException {
            return num1 + num2;
        }

        @Override
        public List<Dog> addDog(Dog dog) throws RemoteException {
            mDogs.add(dog);
            return mDogs;
        }
    };

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

到这里server端已经修改完毕了,我们再看一下server的目录结构:
这里写图片描述

接下来是client端
1.将server目录下src/main下的aidl整个包复制粘贴到client下对应的位置,覆盖原来的文件
2.将server目录下src/main下的Dog文件以及它所在文件夹复制到client下对应的位置
这里写图片描述

然后重新build,修改client端中的逻辑:

public class ClientActivity extends AppCompatActivity {
    private IMyAidl iMyAidl;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidl = IMyAidl.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMyAidl = null;
        }
    };

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

    private void initView() {
        final EditText num1Edt = (EditText) findViewById(R.id.num1);
        final EditText num2Edt = (EditText) findViewById(R.id.num2);
        Button addBtn = (Button) findViewById(R.id.add);
        final TextView resultTv = (TextView) findViewById(R.id.result);
        final TextView printTv = (TextView) findViewById(R.id.print);

        addBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String num1 = num1Edt.getText().toString().trim();
                String num2 = num2Edt.getText().toString().trim();
                if (TextUtils.isEmpty(num1)) {
                    Toast.makeText(ClientActivity.this, "请输入第一个数字", Toast.LENGTH_LONG).show();
                } else if (TextUtils.isEmpty(num2)) {
                    Toast.makeText(ClientActivity.this, "请输入第二个数字", Toast.LENGTH_LONG).show();
                } else {
                    if (iMyAidl != null) {
                        try {
                            int result = iMyAidl.add(Integer.valueOf(num1), Integer.valueOf(num2));
//                            resultTv.setText(result + "");
                            List<Dog> dogs = iMyAidl.addDog(new Dog(result));
                            StringBuffer buffer = new StringBuffer();
                            buffer.append("现在有");
                            for (int i = 0; i < dogs.size(); i++) {
                                buffer.append(dogs.get(i).getAge() + "岁,");
                            }
                            buffer.append("共" + dogs.size() + "只狗");
                            printTv.setText(buffer);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

    private void bindService() {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.aidl.tsnt.server", "com.aidl.tsnt.server.RemoteService"));
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

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

还有对应的layout,activity_client.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_client"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".ClientActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/num1"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:hint="num1" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="+" />

        <EditText
            android:id="@+id/num2"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:hint="num2" />

        <Button
            android:id="@+id/add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="=" />

        <TextView
            android:id="@+id/result"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:textColor="@android:color/holo_red_dark" />
    </LinearLayout>

    <TextView
        android:id="@+id/print"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp" />
</LinearLayout>

最后运行client和server,如下图:
这里写图片描述

至此,AIDL实践完毕。
源码地址:https://github.com/tingshuonitiao/AIDL_practice

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值