Android uses AIDL for communication between two apps and mutual message callback (1)

Foreword:

AIDL: Android Interface Definition Language, translated to Android Interface Definition Language. It is a description language used to define the communication interface between the server and the client, and can be used to generate code for IPC. Therefore, the use of AIDL requires a server and client
role: you can obtain data of another process and call the methods exposed by it in one process to meet the needs of inter-process communication.

1. Basic data types supported by AIDL

  1. Eight basic data types: byte, char, short, int, long, float, double, boolean
  2. String,CharSequence
  3. Implements the data type of the Parcelable interface
  4. List type. The data carried by the List must be of the type supported by AIDL, or other declared AIDL objects
  5. Map type. The data carried by the map must be of the type supported by AIDL, or other declared AIDL objects

2. Implementation of the server

   Create the project and the aidl file required

  • Create a new project using Android Studio, named TestAidlDemo1
  • Right click New an AIDL file, named IAidlInterface, AS will automatically generate an aidl folder with the same path in the project directory
  • Since you want to call back the message, you also need a callback interface. In the same way, create the IAidlCallBack.aidl file, then proceed to write the code

Implement code logic

  • Write IAidlInterface.aldi code, because we need callback messages, then we need to register callback and unregister callback interfaces, an interface to send messages, an interface to get historical messages, the code is as follows ( AIDL files will not be automatically guided, some are not basic support Data types need to be imported manually by ourselves, )
    import com.pgc.testaidldemo1.IAidlCallBack;
    interface IAidlInterface {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void registerCallBack(IAidlCallBack iAidlCallBack);
        void unregisterCallBack(IAidlCallBack iAidlCallBack);
        void sendMessage(String message);
        List<String> getMessages();
    }
    

     

  • Write IAidlCallBack.aidl code: Since it is a callback interface, then we only need a callback interface to send a message successfully, the code is as follows

    interface IAidlCallBack {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void onMessageSuccess(String message);
    }

     

  • Since it is a server, we need to implement the logic code to receive the message and process the message, so we create an AidlService and inherit the Service, because the Service cannot directly receive Callback, but provides RemoteCallbackList to register the callback

    private RemoteCallbackList<IAidlCallBack> callbackList= new RemoteCallbackList<>();

    At the same time, RemoteCallbackList provides beginBroadcast to obtain the number of currently registered callbacks, so we can use this method to perform callback processing ( after using beginBroadcast, you must call finishBroadcast or else you will report beginBroadcast () called while already in a broadcast error )

    final int num=callbackList.beginBroadcast();
    for (int i=0;i<num;i++){
         IAidlCallBack iAidlCallBack=callbackList.getBroadcastItem(i);
         iAidlCallBack.onMessageSuccess(message);
        }
    callbackList.finishBroadcast();

     Next, the binder object is instantiated and returned to the client,

    @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        private final IAidlInterface.Stub binder=new IAidlInterface.Stub() {
            @Override
            public void registerCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.register(iAidlCallBack);
            }
    
            @Override
            public void unregisterCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.unregister(iAidlCallBack);
            }
    
            @Override
            public void sendMessage(String message) throws RemoteException {
                messages.add(message);
                final int num=callbackList.beginBroadcast();
                for (int i=0;i<num;i++){
                    IAidlCallBack iAidlCallBack=callbackList.getBroadcastItem(i);
                    iAidlCallBack.onMessageSuccess(message);
                }
                callbackList.finishBroadcast();
            }
    
            @Override
            public List<String> getMessages() throws RemoteException {
                return messages;
            }
        };

      

  • Register Service in AndroidManifest.xml

    <service android:name=".AidlService"
             android:enabled="true"
             android:exported="true"
                >
        <intent-filter android:priority="1000">
                <action android:name="AIDL.service"></action>
       </intent-filter>
    </service>

     

  • AidlService all code

    package com.pgc.testaidldemo1;
    
    import android.annotation.SuppressLint;
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteCallbackList;
    import android.os.RemoteException;
    
    import androidx.annotation.Nullable;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    /**
     * Created by PengGuiChu on 2020/4/11.
     */
    @SuppressLint("Registered")
    public class AidlService extends Service {
        private RemoteCallbackList<IAidlCallBack> callbackList= new RemoteCallbackList<>();
        private List<String> messages=new ArrayList<>();
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        private final IAidlInterface.Stub binder=new IAidlInterface.Stub() {
            @Override
            public void registerCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.register(iAidlCallBack);
            }
    
            @Override
            public void unregisterCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.unregister(iAidlCallBack);
            }
    
            @Override
            public void sendMessage(String message) throws RemoteException {
                messages.add(message);
                final int num=callbackList.beginBroadcast();
                for (int i=0;i<num;i++){
                    IAidlCallBack iAidlCallBack=callbackList.getBroadcastItem(i);
                    iAidlCallBack.onMessageSuccess(message);
                }
                callbackList.finishBroadcast();
            }
    
            @Override
            public List<String> getMessages() throws RemoteException {
                return messages;
            }
        };
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    }
    

     

  • Because the server and the client implement the mutual message callback, the binder also needs to be obtained through the binderService on the server side, relative to the client, because the server and the AidlService are on the same thread, we can directly binderService

    Intent intent=new Intent(getApplicationContext(),AidlService.class);
    bindService(intent,serviceConnection,BIND_AUTO_CREATE);

    Then instantiate ServiceConnection

    private ServiceConnection serviceConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                
            }
    
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
    
            }
    };

    Then get the binder in onServiceConnected

    iAidlInterface=IAidlInterface.Stub.asInterface(iBinder);
    try {
          iAidlInterface.asBinder().linkToDeath(mDeathRecipient, 0);//监听进程是否消失
          iAidlInterface.registerCallBack(iAidlCallBack);//注册消息回调
          messages.addAll(iAidlInterface.getMessages());//获取历史消息
          listView.setAdapter(arrayAdapter=new ArrayAdapter<> 
          (getApplicationContext(),android.R.layout.simple_list_item_1,messages));
    } catch (RemoteException e) {
           e.printStackTrace();
    }

    DeathRecipient instance

        private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            //当承载IBinder的进程消失时接收回调的接口
            @Override
            public void binderDied() {
                if (null == iAidlInterface) {
                    return;
                }
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);//注销
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                iAidlInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
                iAidlInterface = null;
            }
        };

    iAidlCallBack instance

        private IAidlCallBack iAidlCallBack=new IAidlCallBack.Stub() {
            @Override
            public void onMessageSuccess(String message) {
                if (messages!=null&&arrayAdapter!=null){
                    messages.add(message);
                    handler.sendEmptyMessage(1);
                }
            }
        };

     MainActivity full code

    package com.pgc.testaidldemo1;
    
    
    
    import android.annotation.SuppressLint;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.RemoteException;
    import android.view.View;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    import java.util.ArrayList;
    import java.util.List;
    
    import butterknife.BindView;
    import butterknife.ButterKnife;
    import butterknife.OnClick;
    
    public class MainActivity extends AppCompatActivity {
        @BindView(R.id.list_view)
        ListView listView;
        private IAidlInterface iAidlInterface;
        private int num;
        private List<String> messages=new ArrayList<>();
        private ArrayAdapter arrayAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
            Intent intent=new Intent(getApplicationContext(),AidlService.class);
            bindService(intent,serviceConnection,BIND_AUTO_CREATE);
        }
    
    
        @OnClick(R.id.send_message)
        public void onViewClicked(View view) {
            if (iAidlInterface!=null){
                try {
                    iAidlInterface.sendMessage("消息"+num);
                    num++;
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private ServiceConnection serviceConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                iAidlInterface=IAidlInterface.Stub.asInterface(iBinder);
                try {
                    iAidlInterface.asBinder().linkToDeath(mDeathRecipient, 0);//监听进程是否消失
                    iAidlInterface.registerCallBack(iAidlCallBack);//注册消息回调
                    messages.addAll(iAidlInterface.getMessages());//获取历史消息
                    listView.setAdapter(arrayAdapter=new ArrayAdapter<>(getApplicationContext(),android.R.layout.simple_list_item_1,messages));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
    
            }
        };
    
        private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            //当承载IBinder的进程消失时接收回调的接口
            @Override
            public void binderDied() {
                if (null == iAidlInterface) {
                    return;
                }
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);//注销
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                iAidlInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
                iAidlInterface = null;
            }
        };
    
        private IAidlCallBack iAidlCallBack=new IAidlCallBack.Stub() {
            @Override
            public void onMessageSuccess(String message) {
                if (messages!=null&&arrayAdapter!=null){
                    messages.add(message);
                    handler.sendEmptyMessage(1);
                }
            }
        };
    
        @SuppressLint("HandlerLeak")
        private Handler handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                arrayAdapter.notifyDataSetChanged();
            }
        };
    
        @Override
        protected void onDestroy() {
            //解除注册
            if (null != iAidlInterface && iAidlInterface.asBinder().isBinderAlive()) {
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            //解除绑定服务
            unbindService(serviceConnection);
            super.onDestroy();
        }
    }
    

    At this point, our server is coded to achieve the effect

3. Client implementation

   Create client project

  •      Select the TestAidlDemo1 project and right-click on a new model, named client
  • If the client project can be connected to Service, we directly copy the aidl file of the above project to the main file of the client project, this is to ensure that the path of the aidl file of the two projects is the same

       

  • The calling logic is basically the same as the MainActivity above. One thing to note is that because it is two different processes, here we can not directly bindService to call up the server, but through the following code
    Intent intent=new Intent();
    String ACTION = "AIDL.service";//对应服务端AndroidManifest.xml配置service action:name
    intent.setAction(ACTION);
    intent.setPackage("com.pgc.testaidldemo1");//对应服务端AndroidManifest.xml package
    bindService(intent,serviceConnection,BIND_AUTO_CREATE);

     

  • All code of client MainActivity

    package com.pgc.client;
    
    import android.annotation.SuppressLint;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.RemoteException;
    import android.view.View;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    
    import com.pgc.testaidldemo1.IAidlCallBack;
    import com.pgc.testaidldemo1.IAidlInterface;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import butterknife.BindView;
    import butterknife.ButterKnife;
    import butterknife.OnClick;
    
    public class MainActivity extends AppCompatActivity {
        @BindView(R.id.list_view)
        ListView listView;
        private IAidlInterface iAidlInterface;
        private int num;
        private List<String> messages=new ArrayList<>();
        private ArrayAdapter arrayAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
            Intent intent=new Intent();
            String ACTION = "AIDL.service";
            intent.setAction(ACTION);
            intent.setPackage("com.pgc.testaidldemo1");
            bindService(intent,serviceConnection,BIND_AUTO_CREATE);
        }
    
    
        @OnClick(R.id.send_message)
        public void onViewClicked(View view) {
            if (iAidlInterface!=null){
                try {
                    iAidlInterface.sendMessage("消息"+num);
                    num++;
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private ServiceConnection serviceConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                iAidlInterface=IAidlInterface.Stub.asInterface(iBinder);
                try {
                    iAidlInterface.asBinder().linkToDeath(mDeathRecipient, 0);
                    iAidlInterface.registerCallBack(iAidlCallBack);
                    messages.addAll(iAidlInterface.getMessages());
                    listView.setAdapter(arrayAdapter=new ArrayAdapter<>(getApplicationContext(),android.R.layout.simple_list_item_1,messages));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
    
            }
        };
    
        private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            //当承载IBinder的进程消失时接收回调的接口
            @Override
            public void binderDied() {
                if (null == iAidlInterface) {
                    return;
                }
                iAidlInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
                iAidlInterface = null;
                //断线重来逻辑
            }
        };
    
        private IAidlCallBack iAidlCallBack=new IAidlCallBack.Stub() {
            @Override
            public void onMessageSuccess(String message) {
                if (messages!=null&&arrayAdapter!=null){
                    messages.add(message);
                    handler.sendEmptyMessage(1);
                }
            }
        };
    
        @SuppressLint("HandlerLeak")
        private Handler handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                arrayAdapter.notifyDataSetChanged();
            }
        };
    
        @Override
        protected void onDestroy() {
            //解除注册
            if (null != iAidlInterface && iAidlInterface.asBinder().isBinderAlive()) {
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            //解除绑定服务
            unbindService(serviceConnection);
            super.onDestroy();
        }
    }
    

     

  • running result

Source code download address

https://github.com/pengkongkong/TestAidlDemo1

Published 16 original articles · 19 praises · 40,000+ views

Guess you like

Origin blog.csdn.net/pengguichu/article/details/105456309