AIDL最佳实践

来源:互联网 发布:手机网络不卡玩游戏卡 编辑:程序博客网 时间:2024/06/07 22:10

参考: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.aidlpackage com.aidl.tsnt.server;parcelable Dog;

然后修改IMyAidl.aidl:

// IMyAidl.aidlpackage 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

原创粉丝点击