Android AIDL 简单的2个例子 标准数据类型和自定义数据类型

    xiaoxiao2022-06-25  241

    本文将介绍如何去使用AIDL,这里有2种,一种是传递标准数据类型,另一种是传递自定义数据类型。

    第一种:

    这里分2个项目,一个是AIDL服务端,一个是AIDL客户端。

    服务端:

    1.创建AIDL文件

    右击你的项目,选择new->AIDL->AIDL File

    然后你就能看到代码结构中多了一个AIDL文件

    打开AIDL文件,你会看到这里已经有一个接口了,不用管,这个是系统自动生成的,只是告诉你可以使用哪些数据类型的。然后我们只需要添加一个我们自己的接口。

    // IRemoteService.aidl package com.example.myaidl; // Declare any non-default types here with import statements interface IRemoteService { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); //添加一个接口 int getId(); }

     

    2.创建service,把接口暴露给客户端

    新建一个service,在AndroidMainfest中添加一个action,为了其他apk可以绑定这个service。

    <service android:name=".MyService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.myaidl.service.action" /> </intent-filter> </service>

    在service中实现刚才的AIDL接口

    package com.example.myaidl; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return binder; } private final IRemoteService.Stub binder = new IRemoteService.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } //实现了刚才我们定义的接口,这里就是一个简单的例子,比较简单。 @Override public int getId() throws RemoteException { return 100; } }; }

    服务端的功能已经完成了,下面看如何在客户端(别的程序)如何来使用服务端(这个程序)的接口。

    客户端:

    1.拷贝AIDL文件

    新建一个项目,直接把服务端那个AIDL文件夹拷贝到你的项目中。

    2.绑定service

    客户端去绑定服务端的service,客户端的onServiceConnected()回调函数将会收到一个binder,这个binder就是服务端service那里onBind()返回的,其实就是AIDL接口。

    代码比较简单,点击按钮就去调用一次接口。

    package com.example.myaidlclient; import android.app.Service; import android.content.ComponentName; import android.content.Context; 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.Button; import com.example.myaidl.IRemoteService; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private IRemoteService iRemoteService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.button); button.setOnClickListener(this); } //这是个回调函数,在绑定service的时候要用到的 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("aaron", "Service has connected"); //返回的binder转换成你的接口 iRemoteService = IRemoteService.Stub.asInterface(service); } //正常unbindservice是不走这的 @Override public void onServiceDisconnected(ComponentName name) { Log.i("aaron", "Service has disconnected"); iRemoteService = null; } }; @Override protected void onResume() { Intent intent = new Intent(); //客户端service的报名 intent.setPackage("com.example.myaidl"); //之前service定义的action intent.setAction("com.example.myaidl.service.action"); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); super.onResume(); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); } @Override public void onClick(View v) { try { int i = iRemoteService.getId(); Log.i("aaron", "invoke AIDL interface success " + i); } catch (RemoteException e) { Log.i("aaron", "exception: " + e.getMessage()); e.printStackTrace(); } } }

     

    先把服务端apk装上,然后运行客户端apk

    运行结果:

     

    第二种:

    描述一下,我们要实现的是传送自定义数据类型。我们这传送的是Person类的数据,里面就包含名字和年龄,比较简单。

    直接在第一种方法的项目上做的,所以还留着一些第一种方法的文件。

    服务端:

    就前面2步比较重要,其他基本一样和上面的例子。

    1.添加数据类型的AIDL 

    这个和上面介绍的不太一样,这个AIDL不是用来和客户端通讯的,只是为了在AIDL中能使用自定义类型的数据。

    新建一个Person.aidl文件

    代码如下

    // Person.aidl package com.example.myaidl; parcelable Person;

    代码很简单,就一行。

    2.定义自定义数据类型

    注意:这里的自定义类要和上面的那个aidl的名字,包名都要一样。

    package com.example.myaidl; import android.os.Parcel; import android.os.Parcelable; public class Person implements Parcelable { private String name; private String age; public Person(String name, String age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } @Override public String toString() { return "name: "+name+" age: "+age; } //下面都是自动生成的,也是必须要实现的 protected Person(Parcel in) { name = in.readString(); age = in.readString(); } public static final Creator<Person> CREATOR = new Creator<Person>() { @Override public Person createFromParcel(Parcel in) { return new Person(in); } @Override public Person[] newArray(int size) { return new Person[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeString(age); } }

    下面开始的步骤基本和第一个例子一样

    3.新建一个AIDL

    这个AIDL接口是用来和客户端通讯的。这里就定义了2个方法,一个获取所有的Person数据,一个是根据指定名字,返回指定Person数据。

    注意:这里要导入对应的Person的引用。不然会报aidl'' finished with non-zero exit value 1错误。如果Person.aidl和Person.java包名不一样也会报错。

    // IPersonManager.aidl package com.example.myaidl; // Declare any non-default types here with import statements import com.example.myaidl.Person; interface IPersonManager { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); List<Person> getAll(); List<Person> getByName(String name); }

     

     

    4.创建service,把接口暴露给客户端

    <service android:name=".PersonService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.RESPOND_VIA_MESSAGE"/> </intent-filter> </service>

    这里就简单的弄了一点数据。

    package com.example.myaidl; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import java.util.ArrayList; import java.util.List; public class PersonService extends Service { static List<Person> persons=new ArrayList<>(); static { Person p1=new Person("bob","20"); Person p2=new Person("king","20"); Person p3=new Person("leif","30"); persons.add(p1); persons.add(p2); persons.add(p3); } public PersonService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return binder; } private final IPersonManager.Stub binder=new IPersonManager.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public List<com.example.myaidl.Person> getAll() throws RemoteException { return persons; } @Override public List<com.example.myaidl.Person> getByName(String name) throws RemoteException { List<Person> list=new ArrayList<>(); for(Person p:persons){ if(p.getName().equals(name)) list.add(p); } return list; } }; }

    客户端:

    客户端的方法和第一个例子基本一样,只是多拷贝点文件。

    1.拷贝AIDL和自定义类

    这里要把Person.aidl Person.java IPersonManager.aidl都拷贝过来。

    注意:包名要和服务端一样

    2.绑定service

    和之前一样,绑定service,然后实例化一个aidl,直接用。

    界面比较简单,不上代码了。就是2个按钮,一个获取所以数据,一个根据edittext中输入的名字来获取数据。

    package com.example.myaidlclient; import android.content.ComponentName; import android.content.Context; 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.Button; import android.widget.EditText; import com.example.myaidl.IPersonManager; import com.example.myaidl.Person; import java.util.List; public class Main2Activity extends AppCompatActivity implements View.OnClickListener { private Button button,button1; private EditText editText; private IPersonManager iPersonManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); button=findViewById(R.id.button2); button.setOnClickListener(this); button1=findViewById(R.id.button3); button1.setOnClickListener(this); editText=findViewById(R.id.editText); } private ServiceConnection mConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("aaron", "Service has connected"); iPersonManager=IPersonManager.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.i("aaron", "Service has disconnected"); iPersonManager=null; } }; @Override protected void onResume() { Intent intent=new Intent(); intent.setPackage("com.example.myaidl"); intent.setAction("android.intent.action.RESPOND_VIA_MESSAGE"); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); super.onResume(); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); } @Override public void onClick(View v) { if(v==button){ try { List<Person> all=iPersonManager.getAll(); for (Person p:all){ Log.i("aaron","All person "+p); } } catch (RemoteException e) { e.printStackTrace(); } }else if(v==button1){ String name=editText.getText().toString(); try { List<Person> list=iPersonManager.getByName(name); if(list.isEmpty()){ Log.i("aaron","no "+name); }else { for (Person p:list){ Log.i("aaron","person "+p); } } } catch (RemoteException e) { e.printStackTrace(); } } } }

     

    运行结果:

     

    这里也可以在调用接口的时候传递自定义数据类型,当然你还得模仿Person这样写一个aidl和一个java。比如下面,根据人来查询对应的宠物。

    在定义接口的时候如果参数不是标准数据类型,要在前面加in out inout。

    in表示输入型参数(Server可以获取到Client传递过去的数据,但是不能对Client端的数据进行修改) out表示输出型参数(Server获取不到Client传递过去的数据,但是能对Client端的数据进行修改) inout表示输入输出型参数(Server可以获取到Client传递过去的数据,但是能对Client端的数据进行修改)。

    interface IPetManager { Pet getPet(in Person p); }

     


    最新回复(0)