一、概述
本文几乎全部参考《Android开发艺术探索》(严重抄袭~)。不同的是,对书中实例做了两方面的变更:
1、在Android Studio中实现书中实例;
2、由单一程序下的多进程变为两个程序的多进程。
二、目标
实现由客户端(TestClient)程序与服务端(TestServer)程序之间的通信。客户端添加书籍进服务端,然后从服务端获取书籍列表。
三、创建服务端程序
1、创建实体Book类,实现Parcelable接口:
public class Book implements Parcelable {
private int bookId;
private String bookName;
public Book(int bookId, String bookName){
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
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.writeInt(bookId);
dest.writeString(bookName);
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
'}';
}
}
2、在Project视图下选中包名,右键New->AIDL->AIDL File,默认文件名即可。
3、随之AS在main文件夹下为我们自动生成了aidl文件夹,如下图:
4、修改IMyAidlInterface.aidl为Book.aidl,代码如下:
// Book.aidl
package com.yita.testserver;
// Declare any non-default types here with import statements
parcelable Book;
5、在Book.aidl文件同目录下,创建IBookManager.aidl,代码如下:
// IBookManager.aidl
package com.yita.testserver;
// 必须手动导包
import com.yita.testserver.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
6、选中当前Model(TestServer),点击左侧小锤子(Make Project),可发现在build->generated->source->aidl->debug->当前包名下生成了IBookManager.java文件
7、切换至java->当前包名,右键新建Service,命名为BookManagerService:
public class BookManagerService extends Service {
private ArrayList<Book> mBookList = new ArrayList<>();
private Binder mBinder = new IBookManager.Stub(){
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
public BookManagerService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG", "---->远程服务启动");
mBookList.add(new Book(1, "book1"));
mBookList.add(new Book(2, "book2"));
}
}
至此,服务端程序接近尾声。但还不够,需要给Service设置intent-filter,要不然客户端找不到它呀~
8、设置Manifest文件
添加自定义权限
<permission android:protectionLevel="normal" android:name="yita.testserver.AIDL_SERVICE"/>
Service注册
<!--exported 可被其他进程调用-->
<service
android:name=".BookManagerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.yita.testserver.AIDL_SERVICE"> </action>
</intent-filter>
</service>
四、创建客户端程序
1、复制服务端(TestServer)main目录下的aidl文件夹到客户端(TestClient)main目录下。
2、客户端java目录下新建包名com.yita.testserver,将服务端Book类粘贴进该包下。
上述两步是为了保证客户端与服务端中的aidl相关文件结构一致。
3、选中当前Model(TestClient),点击左侧小锤子(Make Project),可发现在build->generated->source->aidl->debug->当前包名下生成了IBookManager.java文件:
4、客户端远程调用服务端Service,代码如下:
public class MainActivity extends AppCompatActivity {
private ServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动
start();
}
private void start(){
Intent intent = new Intent("com.yita.testserver.AIDL_SERVICE");
intent.setPackage("com.yita.testserver");
if(conn == null){
conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
// 添加书籍
bookManager.addBook(new Book(3, "book3"));
} catch (RemoteException e) {
e.printStackTrace();
}
try {
// 获取书籍
List<Book> bookList = bookManager.getBookList();
for (Book book : bookList) {
Log.e("TAG", "---->book:" + book.toString());
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
// 绑定服务
bindService(intent, conn, BIND_AUTO_CREATE);
}
}
5、别忘了添加服务端定义的权限
<uses-permission android:name="yita.testserver.AIDL_SERVICE"/>