上篇文章使用了Messenger来进行进程间通信,其本质也是使用AIDL。
这次service端模拟一个图书馆,Activity模拟一位读者,读者可以查看图书馆中的图书列表,可以添加图书,当有新图书加入时通知读者(即添加Listener)
添加新进程中的service
AIDL支持的数据类型:
1.AIDL支持Java原始数据类型。
2.AIDL支持String和CharSequence。
3.实现了Parcelable接口的实例。
4.AIDL支持java.util.List和java.util.Map,但是有一些限制。集合中项的允许数据类型包括Java原始类型、String、CharSequence或是android.os.Parcelable。无需为List和Map提供import语句,但需要为Parcelable提供import语句。
5.非原始类型中,除了String和CharSequence以外,其余均需要一个方向指示符。方向指示符包括in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值。
Book封装类,这里需要实现Parcelable接口来实现序列化,在Android studio中可以快速生成,并且实现Parcelable中的方法
public class Book implements Parcelable {
private int id;
private String name;
protected Book(Parcel in) {
id = in.readInt();
name = in.readString();
}
public Book(int id, String name) {
this.id = id;
this.name = name;
}
public static final Creator CREATOR = new Creator() {
@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.writeInt(id);
dest.writeString(name);
}
...省略get/set方法
}
这里开始编写AIDL文件,android studio中可以右键新建AIDL文件。
如果AIDL中使用到了自定义的Parcelable对象,需要新建一个同名的aidl文件,声明它为Parcelable类型,并且他们的包结构是相同的。
// Book.aidl
package com.du.ipc.bean;
parcelable Book;
用来监听添加书籍的Listener的aidl代码:
// IOnBookChangeListener.aidl
package com.du.ipc;
import com.du.ipc.bean.Book;
interface IOnBookChangeListener {
void onChangeBook(in Book book);
}
BookManager.aidl代码:
// IBookManager.aidl
package com.du.ipc;
import com.du.ipc.bean.Book;
import com.du.ipc.IOnBookChangeListener;
interface IBookManager {
List getBookList();
void addBook(in Book book);
void registListener(IOnBookChangeListener listener);
void removeListener(IOnBookChangeListener listener);
}
Activity代码如下:
public class BookActivity extends AppCompatActivity {
private int bookId = 1;
private IBookManager bookManager;
// Service连接
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 连接成功
bookManager = IBookManager.Stub.asInterface(service);
try {
// 注册书籍变化监听器
bookManager.registListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
// 书籍变化监听器实现
private IOnBookChangeListener listener = new IOnBookChangeListener.Stub() {
@Override
public void onChangeBook(Book book) throws RemoteException {
Log.e("tag" , "changeBook : " + book);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book);
// 绑定service
Intent intent = new Intent(this , BookService.class);
bindService(intent , connection , Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
// 解绑service
unbindService(connection);
super.onDestroy();
}
// 获取书籍列表
public void getBookList(View view) throws RemoteException {
List books = bookManager.getBookList();
Log.e("tag" , "books : " + books);
}
// 添加书籍
public void addBook(View view) throws RemoteException {
Book book = new Book(bookId , "AndroidBook" + bookId);
bookManager.addBook(book);
bookId++;
}
// 移除监听器
public void removeListener(View view) {
try {
bookManager.removeListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
service代码:
这里有几点需要注意:
1.监听器,这里必须使用RemoteCallbackList,这是专门远程注册、移除监听器的类,如果使用常用的List,会发现无法移除监听器,大家可以试下,这里就不写出来的
2.循环监听器List时调用listeners.beginBroadcast(),并在使用结束后,调用listeners.finishBroadcast(),并且不可以直接写for (int i = 0;i
public class BookService extends Service {
// 监听器,这里必须使用RemoteCallbackList,这是专门远程注册、移除监听器的类,如果使用常用的List,会发现无法移除监听器,大家可以试下,这里就不写出来的
private RemoteCallbackList listeners = new RemoteCallbackList<>();
// 模拟书籍
private List books = new ArrayList<>();
// 实现我们定义的IBookManager
private IBinder mBinder = new IBookManager.Stub(){
@Override
public List getBookList() throws RemoteException {
return books;
}
@Override
public void addBook(Book book) {
books.add(book);
try {
// 获取listener数量,这里一定要写出来,不可以直接写for (int i = 0;i
这里只是使用!!!!!!!不介绍实现!!!