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
- Oito tipos de dados básicos: byte, char, short, int, long, float, double, boolean
- String , CharSequence
- Implementa o tipo de dados da interface Parcelable
- Tipo de lista. Os dados transportados pela lista devem ser do tipo suportado pelo AIDL ou outros objetos AIDL declarados
- 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