Prólogo
AIDL: lenguaje de definición de interfaz de Android, traducido al lenguaje de definición de interfaz de Android. Es un lenguaje de descripción utilizado para definir la interfaz de comunicación entre el servidor y el cliente, y puede utilizarse para generar código para IPC. Por lo tanto, el uso de AIDL requiere un
rol de servidor y cliente : puede obtener datos de otro proceso y llamar a los métodos expuestos por él en un proceso para satisfacer las necesidades de comunicación entre procesos.
1. Tipos de datos básicos compatibles con AIDL
- Ocho tipos de datos básicos: byte, char, short, int, long, float, double, boolean
- String, CharSequence
- Implementa el tipo de datos de la interfaz Parcelable
- Tipo de lista Los datos transportados por la Lista deben ser del tipo admitido por AIDL u otros objetos AIDL declarados
- Tipo de mapa Los datos transportados por el mapa deben ser del tipo admitido por AIDL u otros objetos AIDL declarados
2. Implementación del servidor
Cree el proyecto y el archivo de ayuda requerido
- Cree un nuevo proyecto con Android Studio, denominado TestAidlDemo1
- Haga clic derecho en Nuevo un archivo AIDL, llamado IAidlInterface, AS generará automáticamente una carpeta de ayuda con la misma ruta en el directorio del proyecto
- Como desea devolver la llamada al mensaje, también necesita una interfaz de devolución de llamada. De la misma manera, cree el archivo IAidlCallBack.aidl y luego escriba el código
Implementar lógica de código
- Escriba el código IAidlInterface.aldi, porque necesitamos mensajes de devolución de llamada, luego necesitamos registrar la devolución de llamada y cancelar el registro de las interfaces de devolución de llamada, una interfaz para enviar mensajes, una interfaz para obtener mensajes históricos, el código es el siguiente (los archivos AIDL no serán guiados automáticamente, algunos no son soporte básico Los tipos de datos deben ser importados manualmente por nosotros mismos )
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(); }
-
Escriba el código IAidlCallBack.aidl: dado que es una interfaz de devolución de llamada, solo necesitamos una interfaz de devolución de llamada para enviar un mensaje correctamente, el código es el siguiente
interface IAidlCallBack { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void onMessageSuccess(String message); }
-
Dado que es un servidor, necesitamos implementar el código lógico para recibir el mensaje y procesar el mensaje, por lo que creamos un AidlService y heredamos el Servicio, porque el Servicio no puede recibir la Devolución de llamada directamente, pero proporciona RemoteCallbackList para registrar la devolución de llamada
private RemoteCallbackList<IAidlCallBack> callbackList= new RemoteCallbackList<>();
Al mismo tiempo, RemoteCallbackList proporciona beginBroadcast para obtener el número de devoluciones de llamada registradas actualmente, por lo que podemos usar este método para realizar el procesamiento de devolución de llamada ( después de usar beginBroadcast, debe llamar a finishBroadcast o, de lo contrario, informará beginBroadcast () llamado mientras ya está en un error de transmisión )
final int num=callbackList.beginBroadcast(); for (int i=0;i<num;i++){ IAidlCallBack iAidlCallBack=callbackList.getBroadcastItem(i); iAidlCallBack.onMessageSuccess(message); } callbackList.finishBroadcast();
A continuación, el objeto de carpeta se instancia y se devuelve al 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; } };
-
Servicio de registro en 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 el 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(); } }
-
Debido a que el servidor y el cliente implementan la devolución de llamada de mensajes mutuos, el binder también debe obtenerse a través de binderService en el servidor. En comparación con el cliente, porque el servidor y el AidlService están en el mismo hilo, podemos vincular directamente
Intent intent=new Intent(getApplicationContext(),AidlService.class); bindService(intent,serviceConnection,BIND_AUTO_CREATE);
Luego instanciar ServiceConnection
private ServiceConnection serviceConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { } @Override public void onServiceDisconnected(ComponentName componentName) { } };
Luego, obtenga la carpeta en 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(); }
Instancia 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; } };
Instancia iAidlCallBack
private IAidlCallBack iAidlCallBack=new IAidlCallBack.Stub() { @Override public void onMessageSuccess(String message) { if (messages!=null&&arrayAdapter!=null){ messages.add(message); handler.sendEmptyMessage(1); } } };
MainActivity código completo
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(); } }
En este punto, nuestro servidor está codificado para lograr el efecto
3. Implementación del cliente
Crear proyecto de cliente
- Seleccione el proyecto TestAidlDemo1 y haga clic derecho en un nuevo modelo, llamado cliente
- Si el proyecto del cliente se puede conectar al Servicio, copiamos directamente el archivo de ayuda del proyecto anterior al archivo principal del proyecto del cliente, para garantizar que la ruta del archivo de ayuda de los dos proyectos sea la misma.
- La lógica de llamada es básicamente la misma que MainActivity anterior. Una cosa a tener en cuenta es que debido a que son dos procesos diferentes, aquí no podemos vincular directamente a Service para llamar al servidor, sino a través del siguiente código
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 el código del 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(); } }
-
Efecto corriente
Dirección de descarga del código fuente