O Android usa o AIDL para comunicação entre dois aplicativos e retorno de chamada de mensagem mútua (1)

Prefácio:

AIDL: Android Interface Definition Language, traduzido para Android Interface Definition Language. É uma linguagem de descrição usada para definir a interface de comunicação entre o servidor e o cliente e pode ser usada para gerar código para IPC. Portanto, o uso do AIDL requer uma função de servidor e cliente
: você pode obter dados de outro processo e chamar os métodos expostos por ele em um processo para atender às necessidades de comunicação entre processos.

1. Tipos de dados básicos suportados pelo AIDL

  1. Oito tipos de dados básicos: byte, char, short, int, long, float, double, boolean
  2. String , CharSequence
  3. Implementa o tipo de dados da interface Parcelable
  4. Tipo de lista. Os dados transportados pela lista devem ser do tipo suportado pelo AIDL ou outros objetos AIDL declarados
  5. Tipo de mapa. Os dados transportados pelo mapa devem ser do tipo suportado pelo AIDL ou outros objetos AIDL declarados

2. Implementação do servidor

   Crie o projeto e o arquivo de ajuda necessário

  • Crie um novo projeto usando o Android Studio, chamado TestAidlDemo1
  • Clique com o botão direito do mouse em Novo arquivo AIDL, denominado IAidlInterface, o AS gerará automaticamente uma pasta aidl com o mesmo caminho no diretório do projeto
  • Como você deseja retornar a mensagem, você também precisará de uma interface de retorno de chamada. Da mesma forma, crie o arquivo IAidlCallBack.aidl e continue a escrever o código

Implementar lógica de código

  • Escreva o código IAidlInterface.aldi, porque precisamos de mensagens de retorno de chamada, depois precisamos registrar interfaces de retorno de chamada e cancelar o registro de interfaces, uma interface para enviar mensagens, uma interface para obter mensagens históricas, o código é o seguinte (os arquivos AIDL não serão guiados automaticamente, alguns não são suporte básico Os tipos de dados precisam ser importados manualmente por nós mesmos )
    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();
    }
    

     

  • Escreva o código IAidlCallBack.aidl: como é uma interface de retorno de chamada, precisamos apenas de uma interface de retorno de chamada para enviar uma mensagem com êxito, o código é o seguinte

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

     

  • Como é um servidor, precisamos implementar o código lógico para receber a mensagem e processar a mensagem, portanto, criamos um AidlService e herdamos o Serviço, porque o Serviço não pode receber diretamente o retorno de chamada, mas RemoteCallbackList é fornecido para registrar o retorno de chamada.

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

    Ao mesmo tempo, RemoteCallbackList fornece beginBroadcast para obter o número de retornos de chamada registrados atualmente, para que possamos usar esse método para executar o processamento de retorno de chamada ( depois de usar beginBroadcast, você deve chamar finishBroadcast, caso contrário, você reportará o beginBroadcast () enquanto estiver em uma transmissão )

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

     Em seguida, o objeto fichário é instanciado e retornado ao cliente,

    @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;
            }
        };

      

  • Registrar serviço no 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 todo o código

    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();
        }
    }
    

     

  • Como o servidor e o cliente implementam o retorno de chamada de mensagem mútua, o fichário também precisa ser obtido por meio do binderService no lado do servidor, em relação ao cliente, porque o servidor e o AidlService estão no mesmo encadeamento, podemos diretamente o binderService

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

    Instancie ServiceConnection

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

    Em seguida, coloque o fichário em 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();
    }

    Instância DeathRecipient

        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;
            }
        };

    Instância iAidlCallBack

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

     Código completo da MainActivity

    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();
        }
    }
    

    Neste ponto, nosso servidor está codificado para obter o efeito

3. Implementação do cliente

   Criar projeto do cliente

  •      Selecione o projeto TestAidlDemo1 e clique com o botão direito do mouse em um novo modelo, denominado client
  • Se o projeto do cliente puder ser conectado ao Serviço, copiamos diretamente o arquivo aidl do projeto acima para o arquivo principal do projeto cliente, para garantir que o caminho do arquivo aidl dos dois projetos seja o mesmo.

       

  • A lógica de chamada é basicamente a mesma que a MainActivity acima.Uma coisa a notar é que, por serem dois processos diferentes, aqui não podemos ligar diretamente o Service para chamar o servidor, mas através do código a seguir
    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);

     

  • Todo o código do cliente 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();
        }
    }
    

     

  • Efeito de corrida

Endereço de download do código fonte

https://github.com/pengkongkong/TestAidlDemo1

Publicado 16 artigos originais · 19 elogios · Mais de 40.000 visualizações

Acho que você gosta

Origin blog.csdn.net/pengguichu/article/details/105456309
Recomendado
Clasificación