AIDL用法

本文依旧参考别人文章,只是用自己的语言重复一遍,只做加深印象和方便查阅之用
原文地址
服务端代码编写 在创建aidl文件之前,先了解一下

  • AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值。
那上面的“非默认支持的数据类型”是什么呢?
AIDL支持的数据类型分为如下几种:
  1. 八种基本数据类型:byte、char、short、int、long、float、double、boolean
  2. String,CharSequence
  3. 实现了Parcelable接口的数据类型
  4. List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
  5. Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
    除了上面之外就是非默认支持的数据格式。
如果AIDL文件中用到了自定义的Parcelable对象 必须创建同名的AIDL文件 并声明为Parcelable类型本例中,我们需要传递是Book类(将其序列化这不用说)
public class Book implements Parcelable { private String name; public String getName() { return name; }public void setName(String name) { this.name = name; }public Book(String name) {this.name = name; }@Override public String toString() { return "book name:" + name; }@Override public int describeContents() { return 0; }@Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.name); }protected Book(Parcel in) { this.name = in.readString(); }public static final Creator CREATOR = new Creator() { @Override public Book createFromParcel(Parcel source) { return new Book(source); }@Override public Book[] newArray(int size) { return new Book[size]; } }; public void readFromParcel(Parcel dest) { name = dest.readString(); } }

提一下,如果使用AS的Parcelable插件序列化是没有最后一个readFromParcel()方法(反正我是没有),需要手动填上。
这时我们new aidl文件,名字为Book,并修改(new出来的aidl文件中有个方法,不用可以删除)
如果出现重名,,则先创建aidl,再创建实体类
修改前
package com.kt.ktservice; interface Book{}

修改后
package com.kt.ktservice; parcelable Book; //注意小写parecelable

以上就是第一种aidl,用来声明实现了Parcelable接口的数据类型。
现在来创建定义接口方法的aidl文件
package com.kt.ktservice; import com.kt.ktservice.Book; //即使是同一个包下也要导入,要注意interface BookController {List getBookList(); void addBookInOut(inout Book book); }

然后make project来生成aidl java代码供我们使用
现在需要来创建一个 Service 供客户端远程绑定了
public class AIDLService extends Service {private final String TAG = "YJM"; private List bookList; public AIDLService() { }@Override public void onCreate() { super.onCreate(); bookList=new ArrayList<>(); initDate(); }private void initDate() { Book book1 = new Book("1"); Book book2 = new Book("2"); Book book3 = new Book("123"); Book book4 = new Book("456"); bookList.add(book1); bookList.add(book2); bookList.add(book3); bookList.add(book4); }private final BookController.Stub stub = new BookController.Stub() {@Override public List getBookList() throws RemoteException { return bookList; }@Override public void addBookInOut(Book book) throws RemoteException { if (book != null) { book.setName("服务器收到了提交的新书"); bookList.add(book); } else { Log.e(TAG, "接收到了一个空对象 InOut"); } }}; @Nullable @Override public IBinder onBind(Intent intent) { return stub; }@Override protected void onStop() { //完了解绑一下好习惯 unbindService(serviceConnection); super.onStop(); }}

最后,服务端还有一个地方需要注意,因为服务端的Service需要被客户端来远程绑定,所以客户端要能够找到这个Service,可以通过先指定包名,之后再配置Action值或者直接指定Service类名的方式来绑定Service
如果是通过指定Action值的方式来绑定Service,那还需要将Service的声明改为如下所示:
AIDL用法
文章图片
客户端代码编写 客户端需要再创建一个新的工程,包名命名为 com.kt.ktclient
首先,需要把服务端的AIDL文件以及Book类复制过来,将 aidl 文件夹整个复制到和Java文件夹同个层级下,不需要改动任何代码(甚至包名)
AIDL用法
文章图片


之后,需要创建和服务端Book类所在的相同包名来存放 Book类 AIDL用法
文章图片
界面代码 xml两个按钮
public class MainActivity extends AppCompatActivity {public BookController bookController; public boolean connect; public List bookList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); intent.setPackage("com.kt.ktservice"); intent.setAction("com.kt.abc"); ** bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); } public void getshu(View view) { if(connect) { try { bookList = bookController.getBookList(); log(); } catch (RemoteException e) { e.printStackTrace(); } } } public void change(View view) { if(connect) { try { bookController.addBookInOut(new Book("这是新书")); } catch (RemoteException e) { e.printStackTrace(); } } } private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bookController = BookController.Stub.asInterface(service); connect=true; } @Override public void onServiceDisconnected(ComponentName name) { connect=false; } }; private voidlog(){ for (Book b: bookList) { Log.e("YJM",b.toString()); } } }

到此为止,客户端获取到了服务端的数据,也向服务端传送了数据,那么服务端怎么回复客服端呢,而不是客户端一直被动查询呢,请看下篇。
最后 定向tag
在服务端的接口aidl文件中void addBookInOut(inout Book book)方法中的参数有个前缀。这个叫做定向Tag有三种。in 、out、inout。
区别在于in是数据只能由客户端传向服务端,服务端对数据的修改不会影响到客户端
Out类型的表现形式是:数据只能由服务端传向客户端,即使客户端向方法接口传入了一个对象,该对象中的属性值也是为空的,即不包含任何数据,服务端获取到该对象后,对该对象的任何操作,就会同步到客户端这边
inout:自然就是两边刷新数据(提一点:两边的数据虽然一样,但是不是同一个对象)
【AIDL用法】tag也不能都用inout,在底层是有开销的

    推荐阅读