A list,
This will be a series of articles around AIDL, including simple use of AIDL, advanced use of AIDL, AIDL source exploration, hope to start from simple to complex, in this process to enable you to master the use of AIDL and the details need to pay attention to, but also through the exploration of AIDL source, so that you can understand the principle of AIDL processing. This is the first article to describe the simple use and details of AIDL.
- AIDL for Android IPC
- AIDL for Android IPC
- Android IPC AIDL
Article vocabulary explanation:
- AS: AndroidStudio development tool
- AIDL file: indicates the AIDL interface created in the AIDL directory
- AIDL class: refers to the class generated by the AIDL file Build
What is AIDL?
The Android system is based on the Linux kernel. In The Linux system, the memory of each Process is isolated from each other, so a method is needed to meet the data transmission between different processes, which is often called inter-process Communication (IPC). IPC is implemented with Binder in Android system. As for why Google chose Binder as THE IPC of Android system, there is no research here. There are many articles on the Internet. We will focus on Android Interface Definition Language, or AIDL, which is an application wrapper for Binder.
What can AIDL do?
When we want to do time-consuming or memory intensive operations in the background, we usually start a service, designate it as a new process, or invoke another application service. This is where cross-processes exist, and the interprocess communication AIDL comes in.
Four, the use of
1. Define the AIDL interface
Right-click on the project package name to expand the menu, select the AIDL item, and enter the file name, as shown in the following image.
AS will create a file directory with the same package name in the main directory and generate an AIDL file, AS shown in the following figure.
Note: The AIDL file content in the figure is not the default style. These are some of the functions added in the example.
Once the file is created, you can remove the default functions and write the code according to the business; But there are a few caveats:
- Method parameters only support Java basic data types, String, CharSequence, List(storage objects also need to comply with), Map(storage objects also need to comply with), Parcelable classes, AIDL classes.
- If the parameter is an object (except for the AIDL class), you need to add the modifier prefix, which has the following three types:
- In passes the data object, but changes on the server do not affect the client;
- Out does not pass the data object, but changes on the server are synchronized to the client;
- Inout is a combination of the above two methods. It can both pass data objects to the server and synchronize changes from the server to the client.
- The object class needs to implement Parcelable for serialization, and create an AIDL file in the same directory as aiDL, and mark it as Parcelable in the file, as shown in the following figure.
4. Implement the Parcelable serialization class, when there is a parameter prefix is out, remember to implement the default constructor; As an argument prefixed with out/inout, it is also necessary to implement readFromParcel(Parcel Parcel), because AIDL class source code will need to use these for object creation or content replacement, will be inAndroid IPC AIDLWe’ll start with a quick look at an example class.
public class MethodObject implements Parcelable {
private String name;
public MethodObject(a){// there are arguments prefixed with out, so you need to implement the default constructor
}
protected MethodObject(Parcel in) {
name = in.readString();
}
public static final Creator<MethodObject> CREATOR = new Creator<MethodObject>() {
@Override
public MethodObject createFromParcel(Parcel in) {
return new MethodObject(in);
}
@Override
public MethodObject[] newArray(int size) {
return newMethodObject[size]; }};public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents(a) {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
public void readFromParcel(Parcel parcel){// there are arguments prefixed with out/inout, so you need to implement this method.
this.name = parcel.readString(); }}Copy the code
After the definition is complete, Make Build and AS will generate the final AIDL class in the Build directory, AS shown in the following figure.
This time really want to use the class are created, and it is important to note, if the client and the server is in the same project, an AIDL interface needs to be defined only once, if customer service client and server are different projects, the AIDL interface will need to define the same a respectively, and take special attention to the client and the server to the same package name directory. Below is a detailed structure diagram for this example.
Client:
Server:
Once the previous AIDL classes have been generated, they are ready to use.
2. Use in Service
1. The client communicates with the server
Stub: MyAIDLInterface.Stub: MyAIDLInterface.Stub: MyAIDLInterface. The Binder class implements the IBinder interface.
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
MyAIDLInterface.Stub stub = newMyAIDLInterface.Stub() {... }; }Copy the code
The client binds the Service.
public class MainActivity extends AppCompatActivity {
private MyAIDLInterface myAIDLInterface = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bind();
}
private void bind(a) {
Intent intent = new Intent();
intent.setAction("com.zhukai.aidlservice.startService");
intent.setComponent(new ComponentName("com.zhukai.aidlservice"."com.zhukai.aidlservice.MyService"));
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLInterface = MyAIDLInterface.Stub.asInterface(service);// Returns a proxy object of the MyAIDLInterface.Stub class passed in by another process, Service
try {
if (null! = myAIDLInterface){ myAIDLInterface.commonMethod();// Then you can call any function defined in the AIDL interface
myAIDLInterface.setStringText("test"); . }}catch(RemoteException e) { e.printStackTrace(); }}@Override
public void onServiceDisconnected(ComponentName name) {
myAIDLInterface = null; } }, Service.BIND_AUTO_CREATE); }}Copy the code
At the core of the ServiceConnection interface’s onServiceConnected() callback, the client-side action object myAIDLInterface is called from stub.asInterface ().
2. The server communicates with the customer service
The client can communicate with the server, so if the business needs the server, call back to the client at random; How can the server actively communicate with the client? In fact, this problem is easy to solve, as mentioned earlier, in the AIDL definition rule parameter is to support AIDL class, by registering an AIDL class object from the client to the server, the server through the AIDL class object to communicate with the client can be realized.
The first step is to create an AIDL file as described above.
Make Build to generate AIDL class.
The client invokes the registration function to pass the AIDL-class object to the server.
private void bind(a) {
// Because it is a different application, only implicit binding can be used here.
Intent intent = new Intent();
intent.setAction("com.zhukai.aidlservice.startService");
intent.setComponent(new ComponentName("com.zhukai.aidlservice"."com.zhukai.aidlservice.MyService"));
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLInterface = MyAIDLInterface.Stub.asInterface(service);
try {
if (null! = myAIDLInterface){ myAIDLInterface.commonMethod(); myAIDLInterface.setStringText("test");
myAIDLInterface.register(callBackAIDLInterface);// Register}}catch(RemoteException e) { e.printStackTrace(); }}@Override
public void onServiceDisconnected(ComponentName name) {
myAIDLInterface = null;
}
}, Service.BIND_AUTO_CREATE);
}
// Create an AIDL interface object for server-side callbacks
CallBackAIDLInterface callBackAIDLInterface = new CallBackAIDLInterface.Stub() {
@Override
public void callBack(a) throws RemoteException {}};Copy the code
Look at the server side.
public class MyService extends Service {
private static final String TAG = MyService.class.getSimpleName();
private List<CallBackAIDLInterface> interfaces = new ArrayList<>();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
MyAIDLInterface.Stub stub = new MyAIDLInterface.Stub() {
... // Irrelevant content is hidden
@Override
public void register(CallBackAIDLInterface aidl) throws RemoteException {
if(! interfaces.contains(aidl)) { interfaces.add(aidl); Log.d(TAG,"Register: successful logout"); }}@Override
public void unregister(CallBackAIDLInterface aidl) throws RemoteException {
if (interfaces.contains(aidl)) {
interfaces.remove(aidl);
Log.d(TAG, "Unregister: Logout succeeded");
} else {
Log.d(TAG, "Unregister: failed to log out"); }}}; }Copy the code
Because it is possible for multiple clients to communicate with the server at the same time, the server stores aiDL-class objects directly in interfaces through which it can actively communicate with the client.
Five, the summary
This article is only about the simple use of AIDL. In fact, there are some advanced uses of AIDL. Please keep reading the series of AIDL articles and try to learn and output higher quality articles.