AIDL初识
Posted yl007
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AIDL初识相关的知识,希望对你有一定的参考价值。
AIDL是一个缩写,全称是android Interface Definition Language,也就是Android接口定义语言。
AIDL的设计是为了实现进程间通信,如同两个进程的桥梁,传输一些特定规格的数据。
Android中实现进程通信的几种方式:
1、Activity (借助Intent调用其他APP的Activity实现跨进程通信)
2、广播接收者(BroadcastReceiver)
3、内容提供者(ContentProvider)
4、AIDL(Android Interface definition language,Android接口定义语言)
AIDL特殊的语法:
文件类型:用AIDL书写的文件的后缀是 .aidl,而不是 .java。
数据类型:
默认支持的数据类型包括:
- Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
- String 类型。
- CharSequence类型。
- List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。
- Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。
- 定向tag:AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。
两种AIDL文件:一类是用来定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型的。一类是用来定义方法接口,以供系统使用来完成跨进程通信的。
AIDL实现跨进程通信:
1、使数据实现Parcelable接口
客户端传入服务端的对象需要经过序列化操作,将数据转化为序列化流传到服务端,再由服务端进行反序列化获取数据。AIDL中实现序列化的方式是实现Parcelable接口。如果是默认支持数据类型则无需进行序列化操作。
in的定向Tag方法为writeToParcel() ,out的定向Tag方法为 readFromParcel()
package com.lypeer.ipcclient; import android.os.Parcel; import android.os.Parcelable; /** * Book.java * * Created by lypeer on 2016/7/16. */ public class Book implements Parcelable{ public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } private String name; private int price; public Book(){} public Book(Parcel in) { name = in.readString(); price = in.readInt(); } 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.writeInt(price); } /** * 参数是一个Parcel,用它来存储与传输数据 * @param dest */ public void readFromParcel(Parcel dest) { //注意,此处的读值顺序应当是和writeToParcel()方法中一致的 name = dest.readString(); price = dest.readInt(); } //方便打印数据 @Override public String toString() { return "name : " + name + " , price : " + price; } }
2、新建AIDL文件
// Book.aidl //第一类AIDL文件 //这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用 //注意:Book.aidl与Book.java的包名应当是一样的 package com.lypeer.ipcclient; //注意parcelable是小写 parcelable Book;
// BookManager.aidl //第二类AIDL文件 //作用是定义方法接口 package com.lypeer.ipcclient; //导入所需要使用的非默认支持数据类型的包 import com.lypeer.ipcclient.Book; interface BookManager { //所有的返回值前都不需要加任何东西,不管是什么数据类型 List<Book> getBooks(); //传参时除了Java基本类型以及String,CharSequence之外的类型 //都需要在前面加上定向tag,具体加什么量需而定 void addBook(in Book book); }
Book.aidl与Book.java的包名应当是一样的。这似乎理所当然的意味着这两个文件应当是在同一个包里面的,然而在 Android Studio如果这样做的话,系统根本就找不到 Book.java 文件,两种解决方法如下:
(1)修改 build.gradle 文件:在 android{} 中间加上下面的内容:
sourceSets { main { java.srcDirs = [‘src/main/java‘, ‘src/main/aidl‘] } }
(2)把 java 文件放到 java 包下去:把 Book.java 放到 java 包里任意一个包下,保持其包名不变,与 Book.aidl 一致。
3、复制相关文件
将在一端的AIDL文件写完后,复制到另一端。(一般情况是服务端写好复制到客户端)
4、编写服务端代码
/** * 服务端的AIDLService.java * <p/> * Created by lypeer on 2016/7/17. */ public class AIDLService extends Service { public final String TAG = this.getClass().getSimpleName(); //包含Book对象的list private List<Book> mBooks = new ArrayList<>(); //由AIDL文件生成的BookManager private final BookManager.Stub mBookManager = new BookManager.Stub() { @Override public List<Book> getBooks() throws RemoteException { synchronized (this) { Log.e(TAG, "invoking getBooks() method , now the list is : " + mBooks.toString()); if (mBooks != null) { return mBooks; } return new ArrayList<>(); } } @Override public void addBook(Book book) throws RemoteException { synchronized (this) { if (mBooks == null) { mBooks = new ArrayList<>(); } if (book == null) { Log.e(TAG, "Book is null in In"); book = new Book(); } //尝试修改book的参数,主要是为了观察其到客户端的反馈 book.setPrice(2333); if (!mBooks.contains(book)) { mBooks.add(book); } //打印mBooks列表,观察客户端传过来的值 Log.e(TAG, "invoking addBooks() method , now the list is : " + mBooks.toString()); } } }; @Override public void onCreate() { super.onCreate(); Book book = new Book(); book.setName("Android开发艺术探索"); book.setPrice(28); mBooks.add(book); } @Nullable @Override public IBinder onBind(Intent intent) { Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString())); return mBookManager; } }
代码分为三个部分:
<service android:name=".service.AIDLService" android:exported="true"> <intent-filter> <action android:name="com.lypeer.aidl"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
5、编写客户端代码
public class AIDLActivity extends AppCompatActivity { //由AIDL文件生成的Java类 private BookManager mBookManager = null; //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中 private boolean mBound = false; //包含Book对象的list private List<Book> mBooks; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_aidl); } /** * 按钮的点击事件,点击之后调用服务端的addBookIn方法 * * @param view */ public void addBook(View view) { //如果与服务端的连接处于未连接状态,则尝试连接 if (!mBound) { attemptToBindService(); Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show(); return; } if (mBookManager == null) return; Book book = new Book(); book.setName("APP研发录In"); book.setPrice(30); try { mBookManager.addBook(book); Log.e(getLocalClassName(), book.toString()); } catch (RemoteException e) { e.printStackTrace(); } } /** * 尝试与服务端建立连接 */ private void attemptToBindService() { Intent intent = new Intent(); intent.setAction("com.lypeer.aidl"); intent.setPackage("com.lypeer.ipcserver"); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStart() { super.onStart(); if (!mBound) { attemptToBindService(); } } @Override protected void onStop() { super.onStop(); if (mBound) { unbindService(mServiceConnection); mBound = false; } } private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(getLocalClassName(), "service connected"); mBookManager = BookManager.Stub.asInterface(service); mBound = true; if (mBookManager != null) { try { mBooks = mBookManager.getBooks(); Log.e(getLocalClassName(), mBooks.toString()); } catch (RemoteException e) { e.printStackTrace(); } } } @Override public void onServiceDisconnected(ComponentName name) { Log.e(getLocalClassName(), "service disconnected"); mBound = false; } }; }
参考文章:http://www.jianshu.com/p/a8e43ad5d7d2
以上是关于AIDL初识的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段