通过使用AIDL在两个应用间实现通信
一、创建 service 端
新建一个 service project 在对应路径下右键 -> new -> AIDL -> AIDL File 系统会帮我们自动生成 AIDL 路径和对应的 AIDL 文件
WechatIMG396.jpeg
生成完成后对应的目录如下:
WechatIMG397.jpeg
编写 IUserCalcAIDL.aidl 文件
//这里只是简单的获取用户名和密码
interface IUserCalcAIDL {
String getUserName();
String getPassWord();
}
在 java 目录下新建一个 service
public class UserService extends Service {
//如果此时没有这个类,重新构建一下项目
private final IUserCalcAIDL.Stub mBind = new IUserCalcAIDL.Stub() {
@Override
public String getUserName() throws RemoteException {
return "mao_kk";
}
@Override
public String getPassWord() throws RemoteException {
return "1234567890";
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBind;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
继续在 AndroidManifest.xml 中配置 service
<service
android:name=".UserService"
//设置外部可以访问
android:enabled="true"
android:exported="true">
<intent-filter>
//配置 action 5.0以后不能使用隐式方式访问,所以要设置
<action android:name="com.androidtv.aidlservice.AIDLService" />
</intent-filter>
</service>
到这里 service 端的配置完成,此时的目录结构为:
WechatIMG398.jpeg
运行该项目,等待
二、创建 client 端
新建一个 client project 在对应的路径下将 service 端下的 aidl 文件夹拷贝过来,此时项目结构为:
WechatIMG399.jpeg
注意,如果手动编写 aidl 文件夹,需要包名和 service 端的相对应,下面来编写 MainActivity ,MainActivity中只有几个按钮,bindService 、获取用户名、获取密码,布局简单,就不贴 xml 代码了
private IUserCalcAIDL mIUserCalcAIDL;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("TAG", "onServiceConnected: ---->");
mIUserCalcAIDL = IUserCalcAIDL.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("TAG", "onServiceDisconnected: ----->");
mIUserCalcAIDL = null;
}
};
private void bindAIDLService() {
//5.0 之后不能隐式启动
Intent intent = new Intent();
intent.setAction("com.androidtv.aidlservice.AIDLService");
intent.setPackage("com.androidtv.aidlservice");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private void getPassWord() {
if (mIUserCalcAIDL != null) {
try {
//获取密码 这里得到的就是 1234567890
String passWord = mIUserCalcAIDL.getPassWord();
Toast.makeText(this, passWord, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服务未连接", Toast.LENGTH_SHORT).show();
}
}
private void getUserName() {
if (mIUserCalcAIDL != null) {
try {
//获取用户名 这里的到的就是 mao_kk
String passWord = mIUserCalcAIDL.getUserName();
Toast.makeText(this, passWord, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服务未连接", Toast.LENGTH_SHORT).show();
}
}
到这里,一个简单的 AIDL 就结束了,需要注意的是,如果需要使用自定义的数据类型需要进行配置
三、自定义数据类型
在 service 端中 java 目录下新增需要的自定义类型,注意:该类型是需要实现 Parcelable 接口
//自定义 Book 类型,里面包含一个 bookName 字段
public class Book implements Parcelable {
private String bookName;
protected Book() {
}
protected Book(Parcel in) {
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.writeString(bookName);
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
}
在 aidl 目录下新增 Book.aidl 文件,定义自定义类型
// IUserCalcAIDL.aidl
package com.androidtv.aidlservice;
// 定义 Book
parcelable Book;
重新编写 IUserCalcAIDL.aidl 文件
package com.androidtv.aidlservice;
// import 导入自定义类型
import com.androidtv.aidlservice.Book;
interface IUserCalcAIDL {
String getUserName();
String getPassWord();
//获取 books 列表
List<Book> getBooks();
//往 books 列表中增加数据
//注意 需要在类型前加 in
void addBook(in Book book);
}
重新编译项目,修改 UserService 内容
public class UserService extends Service {
List<Book> mBookList = new ArrayList<>();
//多了两个实现方法
private final IUserCalcAIDL.Stub mBind = new IUserCalcAIDL.Stub() {
@Override
public String getUserName() throws RemoteException {
return "mao_kk";
}
@Override
public String getPassWord() throws RemoteException {
return "1234567890";
}
@Override
public List<Book> getBooks() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
@Override
public void onCreate() {
super.onCreate();
//默认增加一个book
Book book = new Book();
book.setBookName("语文");
mBookList.add(book);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBind;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
此时 service 端的结构为
WechatIMG403.jpeg
service 端的修改完成,接下来修改 client 端,将 service 端下的aidl 文件夹重新拷贝一份到 client 端 中,同时将自定义的数据类型也拷贝过去,注意:自定义类型的包名需要和 service 端的相对应,完成后 client 端的项目结构为:
WechatIMG400.jpeg
在 MainActivity 中可以有对应操作代码
private void addBookList() {
if (mIUserCalcAIDL != null) {
try {
Book book = new Book();
book.setBookName("数学");
mIUserCalcAIDL.addBook(book);
List<Book> books = mIUserCalcAIDL.getBooks();
for (Book book1 : books) {
Log.e("TAG", "addBookList: --->" + book1.getBookName());
}
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服务未连接", Toast.LENGTH_SHORT).show();
}
}
private void getBookList() {
if (mIUserCalcAIDL != null) {
try {
List<Book> books = mIUserCalcAIDL.getBooks();
for (Book book : books) {
Log.e("TAG", "getBookList: ----->" + book.getBookName());
}
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "服务未连接", Toast.LENGTH_SHORT).show();
}
}
到此结束
网友评论