本文主要记录Android Studio下AIDL的实现流程
一、服务端实现
1.创建Book类
Book类在包名对应根目录下(这里包名为com.example.lgf.aidl),否则会有问题,Book类在AIDL中用到,因此要实现Parcelable接口,代码如下:
package com.example.lgf.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
public int index;
public String name;
public Book(int index, String name) {
this.index = index;
this.name = name;
}
protected Book(Parcel in) {
index = in.readInt();
name = 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(index);
dest.writeString(name);
}
}
2.创建IBookManager.aidl文件
在Project模式下,右键module中的任何文件,然后选择New–>AIDL–>AIDL File,如下图:
然后,在弹出的对话框中输入AIDL文件名,这里以IBookManager为例,如下图
输入文件名后会在main下生成aidl目录并生成对应包名和AIDL文件,如下图
修改IBookManager.aidl文件,去除默认方法,添加addBook方法和getBookList方法,代码如下:
// IBookManager.aidl
package com.example.lgf.aidl;
// Declare any non-default types here with import statements
import com.example.lgf.aidl.Book; // 1
interface IBookManager {
void addBook(in Book book); // 2
List<Book> getBookList();
}
需要注意的是,上面代码注释中,标记1:表示需要导入所用到的类,因为这里用到了Book类;标记2:除了基本数据类型外,其它类型的参数必须标上方向(in、out或者inout,in表示输入型参数,out表示输出型参数,inout表示出入输出型)。
3.创建Book.aidl文件
如果AIDL文件中用到了自定义的Parcelable对象,则须创建一个和它同名的AIDL文件
因为IBookManager.aidl文件中用到了自定义的Parcelable对象Book,因此必须创建和Book同名的Book.aidl文件,在IBookManager.aidl所在包中右键选择New–>File,在弹出的对话框中输入Book.aidl,然后添加如下代码:
package com.example.lgf.aidl;
parcelable Book;
AIDL中每个实现了Parcelable接口的类都需要按照上面代码这种方式去创建相应的AIDL文件,并声明那个类为parcelable。
4.编译项目
执行上述操作后编译项目,然后会在相应module的 build/generated/source/aidl/debug/包名 下生成相应的类,如下图:
5.远程服务端实现
创建Binder对象并在onBind返回它,这个对象继承自IBookManager.Stub并实现了它内部的AIDL方法。
package com.example.lgf.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BookManagerService extends Service {
private List<Book> bookList = new ArrayList<>();
private Binder binder = new IBookManager.Stub() {
@Override
public void addBook(Book book) throws RemoteException {
bookList.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
return bookList;
}
};
@Override
public void onCreate() {
super.onCreate();
bookList.add(new Book(1, "JAVA"));
bookList.add(new Book(2, "Android"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
6.注册Service
在AndroidManifest.xml中添加如下代码
<service android:name=".BookManagerService" android:exported="true"/>
自此远程服务端算是搞好了。
二、客户端实现
客户端按多进程是否属于同一应用的实现又稍微有点不一样。
1.同一应用的不同进程
如果是同一应用的不同进程,则需要将服务端的service注册增加android:process属性,如下:
<service android:name=".BookManagerService" android:process=":remote"/>
此时,同一module中,客户端实现代码如下:
package com.example.lgf.aidl;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private IBookManager iBookManager;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
try {
iBookManager.addBook(new Book(3, "Kotlin"));
List<Book> bookList = iBookManager.getBookList();
Log.d("MainActivity", "book size-->" + bookList.size());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(new Intent(this, BookManagerService.class), serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
2.不同应用
如果是不同的应用,则需要把服务端的aidl文件以及相关的实现Parcelable类,原原本本的复制到客户端,包名也要一样,如下图:
接着编译下工程,然后会在module的 build/generated/source/aidl/debug/包名 下生成相应的类,和之前的一样。
最后客户端的实现代码如下:
package com.example.lgf.myapplication;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.example.lgf.aidl.Book;
import com.example.lgf.aidl.IBookManager;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private IBookManager iBookManager;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
try {
iBookManager.addBook(new Book(3, "Python"));
List<Book> bookList = iBookManager.getBookList();
Log.d("MainActivity", "book size-->" + bookList.size());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(Intent.ACTION_MAIN); // 1
ComponentName componentName = new ComponentName("com.example.lgf.aidl", "com.example.lgf.aidl.BookManagerService"); // 2
intent.setComponent(componentName); // 3
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
此处需要注意的是,代码注释中,标注1:意图要用Intent.ACTION_MAIN;标注2:ComponentName构造方法参数中,第一个为服务端的包名,第二个是要绑定的服务端的服务名;标注3:要启动其它应用组件需要调用setComponent方法,因为Android5.0以后不用隐式启动。
另外,服务端的MainActivity需要修改服务的启动方式,改为如下:
package com.example.lgf.aidl;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent service = new Intent(this, BookManagerService.class);
startService(service);
}
@Override
protected void onDestroy() {
super.onDestroy();
Intent service = new Intent(this, BookManagerService.class);
stopService(service);
}
}
运行客户端前先运行服务端app,自此,不同应用的AIDL通信已完成。
附:
示例代码:git@github.com:Geroff/AIDLTest.git的develop分支,tag中v1是同一应用多进程的AIDL,v2是不同应用的AIDL