1. Introduction to AIDL
1. IPC
IPC (Inter-Process Communication): means inter-process communication or cross-process communication.
A process generally refers to an execution unit, which has an independent address space, that is, an application or a program.
A thread is the smallest unit of CPU scheduling, and it is an execution part or execution body in a process.
Processes contain threads. Because resources between processes cannot be shared, each system needs its own IPC mechanism. Android is an operating system based on the Linux kernel, but it does not inherit the IPC mechanism of Linux, but has its own IPC mechanism.
2. Binder
Binder is the most characteristic IPC method in Android. AIDL is realized through Binder. After we define the aidl file, Android Studio will help us generate related Binder classes. In fact, the Stub class we inherit when using AIDL is the Binder class generated by Android studio for us, so we can understand the working principle of Binder by looking at the code generated by Android studio.
3. AIDL
Each process has its own Dalvik VM instance, has its own independent memory, stores its own data in its own memory, and performs its own operations. We can use AIDL to make some rules about what exchanges they can have.
AIDL (Android Interface definition language, Android Interface Definition Language) is a kind of IPC (Inter-process Communication) method in Android. In simple terms, the function of AIDL is that you can bind the service of another APP in your own APP, so that Two APPs can interact. AIDL is mainly used in Android inter-process communication. AIDL automatically generates Binder-related code for us. We don’t need to manually write complex Binder classes. We only need to write our own business methods for calling remote services in the AIDL interface file. That's it, simplifying the development process.
BroadcastReceiver and Messenger can also communicate, but BroadcastReceiver occupies more system resources, and it is obviously not advisable if it is frequent cross-process communication; when Messenger performs cross-process communication, the request queue is synchronous and cannot be executed concurrently.
2. AIDL syntax
ADIL syntax is similar to Java syntax, mainly in the following points:
-
File type: The file extension is .aidl
-
Data type: AIDL supports some data types by default. It is not necessary to import packages when using these data types, but data types other than these types must be imported before use, even if the target file is different from the current . aidl file in the same package - in Java, this case does not need to import the package. For example: Now we have written two files, one is called Book.java, the other is called BookManager.aidl, they are all under the
com.lypeer.aidldemo
package, now we need to use the Book object in the .aidl file, then we must in the .aidl file Write itimport com.lypeer.aidldemo.Book
; even if the .java file and the .aidl file are in one package.Data types supported by AIDL
- Basic data types (int, long, char, boolean, double, etc.);
- String和CharSequence;
- List: Only ArrayList is supported, and each element in it must also be a type supported by AIDL;
- Map: only HashMap is supported, and each key and value in it must be a type supported by AIDL;
- Parcelable: all objects that implement the Parcelable interface;
- AIDL: All AIDL interfaces themselves can also be used in AIDL;
-
Orientation tag: The orientation tag in AIDL indicates the flow of data in cross-process communication, where in means that data can only flow from the client to the server, out means that the data can only flow from the server to the client, and inout means that the data can only flow from the server to the client. Two-way flow between server and client. Wherein, the data flow direction refers to the object of the incoming method in the client. If in is a directional tag, it means that the server will receive a complete data of that object, but the object on the client will not change due to the modification of the parameters passed by the server; if out, it means that the server will receive the data The empty object of the object, but the client will change it synchronously after the server modifies the received empty object; if inout is a directional tag, the server will receive the complete information of the object from the client, And the client will synchronize any changes made to the object by the server.
The basic type and String in Java, the directional tag of CharSequence can only be in by default
-
Two kinds of AIDL files: one is used to define parcelable objects for other AIDL files to use data types not supported by default in AIDL. The other type is used to define method interfaces for use by the system to complete cross-process communication.
All non-default supported data types must be defined by the first class AIDL file before they can be used.
Example:
// Book.aidl //第一类AIDL文件的例子 //这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用 //注意:Book.aidl与Book.java的包名应当是一样的 package com.lypeer.ipcclient; //注意parcelable是小写 parcelable Book;
// BookManager.aidl //第二类AIDL文件的例子 package com.lypeer.ipcclient; //导入所需要使用的非默认支持数据类型的包 import com.lypeer.ipcclient.Book; interface BookManager { //所有的返回值前都不需要加任何东西,不管是什么数据类型 List<Book> getBooks(); Book getBook(); int getBookCount(); //传参时除了Java基本类型以及String,CharSequence之外的类型 //都需要在前面加上定向tag,具体加什么量需而定 void setBookPrice(in Book book , int price) void setBookName(in Book book , String name) void addBookIn(in Book book); void addBookOut(out Book book); void addBookInout(inout Book book); }
3. Use of AIDL
Using AIDL in Android studio, because two APPs interact, so we need two APPs. One is the client side and the other is the service side.
step:
1. Declaration file: Create an AIDL file on the server side to generate javaBean and interface for transfer calls.
2. Create a service: Create a Service on the server side and implement the above interface.
3. Binding service: The client binds the Service.
4. Cross-process call: the client calls the server interface.
Example:
Create an aidl file and define two methods in the aidl file. Create IMyService.adil
the file as shown.
After the creation is complete, click Make Build to automatically compile the generated
IMyService.java
file.IMyService.java
The internal class Stub class is defined in , inherits Binder, and implementsIMyService.aidl
the interface in the file we defined.
Create a Service, inherit the Stub class generated by compiling the aidl file in the Service, and rewrite the methods defined in the interface in the aidl file. Create AIDLService.java
a file, inherit IMyService.Stub
, and override IMyService.aidl
the method defined by the interface in the file.
//AIDLService.java
public class AIDLService extends Service {
//定义Service ACTION,在AndroidManifest.xml中注册
public static final String ACTION = "com.android.service.AIDLService";
private static final String TAG = "AIDLService";
private MyBinder myBinder;
public AIDLService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand....");
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i(TAG,"onBind");
myBinder = new MyBinder();
return myBinder;
}
public class MyBinder extends IMyService.Stub{
@Override
public void play() throws RemoteException {
Log.i(TAG,"Service自定义play()...");
}
@Override
public void pause() throws RemoteException {
Log.i(TAG,"Service自定义pause()...");
}
}
}
AndroidManifest.xml
Register the service in
Copy the aidl file from the server to the client. Copy the files in the Service IMyService.aidl
together with the package name to the Client.
Call the Service interface in the Client. MainActivity.java
Call the interface defined by Service in Client .
//MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final String TAG = "AIDLClient";
Button btnBind,btnPlay,btnPause;
IMyService mBinder;
boolean mIsBind = false;
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
/*
* 获得另一个进程中的Service传递过来的IBinder对象-service,
* 用IMyService.Stub.asInterface方法转换该对象,这点与进程内的通信不同
*/
Log.i(TAG, "onServiceConnected....");
mBinder = IMyService.Stub.asInterface(service);
mIsBind = true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnBind = (Button) findViewById(R.id.butBind);
btnPlay = (Button) findViewById(R.id.butPlay);
btnPause = (Button) findViewById(R.id.butPause);
btnBind.setOnClickListener(this);
btnPlay.setOnClickListener(this);
btnPause.setOnClickListener(this);
}
@Override
public void onClick(View view) {
Intent intent = new Intent();
int btn = view.getId();
switch (btn){
case R.id.butBind:
Log.i(TAG,"btnBind========" + "mIsBind = " + mIsBind);
intent.setPackage("com.example.aidl_test");
intent.setAction("com.android.service.AIDLService");
bindService(intent, mConn, BIND_AUTO_CREATE);
break;
case R.id.butPlay:
Log.i(TAG,"play()========" + "mIsBind = " + mIsBind);
if (mIsBind){
Log.i(TAG,"play()");
try {
mBinder.play();
}catch (RemoteException e){
e.printStackTrace();
}
}
break;
case R.id.butPause:
Log.i(TAG,"pause()");
if (mIsBind){
Log.i(TAG,"pause()");
try {
mBinder.pause();
}catch (RemoteException e){
e.printStackTrace();
}
}
break;
}
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
}
operation result: