Detailed explanation of AIDL, try to implement the AIDL mechanism by yourself

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 it  import com.lypeer.aidldemo.Book; even if the .java file and the .aidl file are in one package.

    Data types supported by AIDL

    1. Basic data types (int, long, char, boolean, double, etc.);
    2. String和CharSequence;
    3. List: Only ArrayList is supported, and each element in it must also be a type supported by AIDL;
    4. Map: only HashMap is supported, and each key and value in it must be a type supported by AIDL;
    5. Parcelable: all objects that implement the Parcelable interface;
    6. 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.adilthe file as shown.
insert image description here

After the creation is complete, click Make Build to automatically compile the generated IMyService.javafile. IMyService.javaThe internal class Stub class is defined in , inherits Binder, and implements IMyService.aidlthe interface in the file we defined.
insert image description here

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.javaa file, inherit IMyService.Stub, and override IMyService.aidlthe method defined by the interface in the file.
insert image description here

//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.xmlRegister the service in
insert image description here

Copy the aidl file from the server to the client. Copy the files in the Service IMyService.aidltogether with the package name to the Client.
insert image description here
Call the Service interface in the Client. MainActivity.javaCall the interface defined by Service in Client .
insert image description here

//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:

insert image description here

Guess you like

Origin blog.csdn.net/qq_43880417/article/details/120028035