Русские Блоги
Android межпроцессное взаимодействие AIDL подробное объяснение (с исходным кодом)
обзор
AIDL: язык определения интерфейса Android, то есть язык определения интерфейса Android, помните, что это язык, цель которого предназначена для обеспечения межпроцессного взаимодействия, мы знаем, что каждый процесс Android выполняется в отдельной памяти, процесс Интеркод не может быть вызван счастливо, но в нашем развитии неизбежно будут некоторые сценарии, когда требуется вызов метода в реальном времени и передача данных.
Типы данных, поддерживаемые AIDL
- Основные типы данных JAVA (байтовый, короткий, int, длинный, float, double, boolean, char)
- Строка и Charsequence
- Список, поддерживает только ArrayList, где объекты должны быть сериализованы
- Карта, поддерживает только HashMap, где объекты должны быть сериализованы
- Объекты, которые реализуют интерфейс android.os.Parcelable
- AIDL автоматически сгенерированный интерфейс
Этапы реализации AIDL
Шаг 1: Создать проект
Поскольку AIDL является межпроцессным взаимодействием, мы должны сначала определить два проекта, которые мы определяем как:
Клиент: AIDLClientDmeo
Сервер: AIDLServerDmeo (на сервере должна быть реализована служба Service)
Создать проект просто, и этот процесс здесь игнорируется;
Шаг 2: Определите интерфейс AIDL
Создайте файл, заканчивающийся на .aidl, через Android Studio. Чтобы понять, что два процесса могут вызывать друг друга, определите два aidl: IFirstAidlInterface.aidl и ICallbackInterface.aidl
package com.ailian.study; interface IServerListener < void backByServer(String param); > package com.ailian.study; import com.ailian.study.IServerListener; // Обратите внимание, что это необходимо ввести вручную interface IFirstAidlInterface < void callServer(String type,IServerListener callback); >
Замечания по поводу определения интерфейса AIDL:
- Интерфейс AIDL должен быть определен в двух процессах, которые взаимодействуют друг с другом, и путь к файлу и имя файла должны быть согласованы. Это очень важно, иначе связь будет невозможна;
Шаг 3: Компиляция
После определения интерфейса AIDL сначала необходимо скомпилировать проект, поскольку после компиляции IDE автоматически сгенерирует для нас файл JAVA с таким же именем в каталоге app / build / generate / source / aidl / debug /. Вам не нужно обращать внимание на то, как создается этот файл. , Автоматически сгенерированный файл доступен только для чтения и не может быть изменен; мы не будем объяснять содержание, сгенерированное внутри;
Четвертый шаг: AIDLServerDmeo реализует Сервис
На предыдущих этапах мы определили интерфейс AIDL в обоих проектах. Теперь мы можем реализовать Service на стороне сервера и предоставить его другим пользователям, чтобы они связывались;
package com.ailian.study.aidlserverdemo; import android.app.Service; import android.content.Intent; import android.os.IBinder; /** * Created by ailian on 2018/6/9/009. */ public class AidlService extends Service private AidlServiceSub mServiceStub; @Override public void onCreate() < super.onCreate(); mServiceStub = new AidlServiceSub(); > @Override public IBinder onBind(Intent intent) < /** * Здесь будет возвращен объект связующего, получить этот объект в клиенте */ return mServiceStub; > @Override public boolean onUnbind(Intent intent) < return super.onUnbind(intent); > >
В методе onBind есть возвращаемое значение объекта IBinder. Клиент может получить этот объект IBinder через интерфейс bindService. AidlServiceSub должен наследовать объект IFirstAidlInterface.Stub, автоматически сгенерированный IFirstAidlInterface:
package com.ailian.study.aidlserverdemo; import android.os.RemoteException; import android.util.Log; import com.ailian.study.IFirstAidlInterface; import com.ailian.study.IServerListener; /** * Created by ailian on 2018/6/9/330. */ public class AidlServiceSub extends IFirstAidlInterface.Stub @Override public void callServer(String type, IServerListener callback) throws RemoteException < Log.d("AidlServiceSub", «Сообщение от клиента:» + type); callback.backByServer("Желтая река Желтая река, я тоже Желтая река"); > >
Пятый шаг: AIDLServerDmeo реализует Сервис
Объявите службу, созданную на четвертом этапе, в файле AndroidManifest.xml AIDLServerDemo
android: exported = ”true” // Запустить другое приложение для запуска
android: process = «: remote» // Запустить в отдельном процессе
// Вам нужно настроить действие для других процессов, чтобы запустить службу и передать этот параметр:
service android:name=".AidlService" android:exported="true" android:process=":remote"> intent-filter> action android:name="android.ailian.aidl.test" /> category android:name="android.intent.category.DEFAULT" /> intent-filter> service>
Шаг 6: AIDLClientDmeo запускает Сервис
После выполнения описанных выше пяти шагов клиент может установить канал связи с сервером через bindService:
Intent it = new Intent(); it.setAction("android.ailian.aidl.test"); it.setPackage("com.ailian.study.aidlserverdemo"); bindService(it, mserviceConnection, BIND_AUTO_CREATE);
Здесь есть mserviceConnection, который является обратным вызовом для вызова bindService.
ServiceConnection mserviceConnection = new ServiceConnection() < @Override public void onServiceDisconnected(ComponentName name) < /** * Обратный вызов для неудачной привязки */ bindServiceTip.setText(«Привязка службы не удалась, пожалуйста, повторите привязку»); clientContent.setText(""); > @Override public void onServiceConnected(ComponentName name, IBinder service) < /** * Обратный вызов для успешного связывания, когда получен объект IBinder, мы используем этот IBinder для связи с Сервером */ bindServiceTip.setText(«Служба привязки успешно завершена, и связь возможна»); clientContent.setText(""); executeService = IFirstAidlInterface.Stub.asInterface(service); > >;
Сделай это, давайте проверим это
Результаты валидации
Мы устанавливаем 2 приложения на одном телефоне одновременно
Прямой тест по мобильному телефону, успешный тест может общаться друг с другом;
Шаги без исходного кода — все трюки
Приложите адрес загрузки исходного кода, я надеюсь помочь вам:
Русские Блоги
2) После написания файла AIDL необходимо создать —> сделать модуль «AIDLSERVERDEMO» для создания соответствующего файла Java.
Каталог файлов iPerson.java выглядит следующим образом:
3) Реализация интерфейса AIDL (IPERSONIMPL)
package com.example.aidlserverdemo; import android.os.RemoteException; public class IPersonImpl extends IPerson.Stub < // объявляю две переменные private int age; private String name; @Override public void setAge(int age) throws RemoteException < this.age = age; >@Override public void setName(String name) throws RemoteException < this.name = name; >@Override public String display() throws RemoteException < return "name:zzz;age=18"; >>
package com.example.aidlserverdemo; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; public class MyRemoteService extends Service < // объявляю интерфейс iPerson private Binder iPerson; @Override public void onCreate() < super.onCreate(); if (iPerson == null) < iPerson = new IPersonImpl(); >> @Override public IBinder onBind(Intent intent) < return iPerson; >>
6) Открытое обслуживание
Обратите внимание, что есть два яма, первое — это меры ожидания должны написать действие AndroidManifest.xml;
package com.example.aidlserverdemo; import android.content.Intent; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); // Установить атрибут активности намерения intent.setAction("com.example.aidlserverdemo.MyRemoteService"); Intent finalIntent = IntentUtils.createExplicitFromImplicitIntent(this, intent); // Общая служба startService(finalIntent); >>
Вторая яма — преобразовать неявное намерение отображаемого намерения
package com.example.aidlserverdemo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import java.util.List; public class IntentUtils < /*** * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent, * "java.lang.IllegalArgumentException: Service Intent must be explicit" * * If you are using an implicit intent, and know only 1 target would answer this intent, * This method will help you turn the implicit intent into the explicit form. * * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466 * @param context * @param implicitIntent - The original implicit intent * @return Explicit Intent created from the implicit original intent */ public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) < // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); ListresolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) < return null; >// Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; > >
Затем запустите службу, потому что клиент основан на обслуживании, должен быть включен.
Скопируйте iPerson.aidl сервера и выполнить сборку —> сделать модуль «AIDLSERVERDEMO»
1) Создайте объект ServiceConnection
// Институт инстанционного серверанника private ServiceConnection conn = new ServiceConnection() < @Override synchronized public void onServiceConnected(ComponentName name, IBinder service) < Log.d("MainActivity","onServiceConnected()---------->"); // Получить интерфейс iPerson iPerson = IPerson.Stub.asInterface(service); Log.d("MainActivity","iperson----------:" + iPerson); > @Override public void onServiceDisconnected(ComponentName name) < Log.d("MainActivity","onServiceDisconnected()---------->"); iPerson = null; > >;
Обратите внимание, что есть также яма, вы должны добавить пакет и действие, пакет — это имя пакета сервера, действие — это действие сервиса выше.
Intent intent = new Intent(); // Вы должны добавить это в 5,0 и выше. intent.setPackage("com.example.aidlserverdemo"); Intent.Setaction («com.example.aidlserverdemo.myremoteservice); // Это обслуживание вышеуказанного обслуживания bindService(intent, conn, Service.BIND_AUTO_CREATE);
btn.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < try < String msg = iPerson.display(); // Способ возвращения метода отображения Log.d("MainActivity", "msg====-->" + msg); > catch (Exception e) < Log.d("MainActivity", "e====-->" + e); e.printStackTrace(); > > >);
@Override protected void onDestroy() < if (conn != null) < unbindService(conn); >super.onDestroy(); >
5) Запустите результаты:
2020-07-02 09:56:20.461 9151-9151/com.example.aidlclientdemo D/MainActivity: msg====-->name:zzz;age=18
Aidlserverdemo что это за программа на Андроид
1.aidl service end
1) Create aidl file
Will generate an IPerson.aidl file
// IPerson.aidl package com.example.aidlserverdemo; // Declare any non-default types here with import statements interface IPerson
2) After the aidl file is written, you need to Build—>Make Module’aidlserverdemo’ to generate the corresponding java file.
The IPerson.java file directory is as follows:
3) The realization class of aidl interface (IPersonImpl)
package com.example.aidlserverdemo; import android.os.RemoteException; public class IPersonImpl extends IPerson.Stub < // Declare two variables private int age; private String name; @Override public void setAge(int age) throws RemoteException < this.age = age; >@Override public void setName(String name) throws RemoteException < this.name = name; >@Override public String display() throws RemoteException < return "name:zzz;age=18"; >>
package com.example.aidlserverdemo; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; public class MyRemoteService extends Service < // Declare IPerson interface private Binder iPerson; @Override public void onCreate() < super.onCreate(); if (iPerson == null) < iPerson = new IPersonImpl(); >> @Override public IBinder onBind(Intent intent) < return iPerson; >>
6) Turn on the service
Note that there are two pits here. The first one is that the action of the Intent must write the action of the service in AndroidManifest.xml;
package com.example.aidlserverdemo; import android.content.Intent; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); // Set the Action property of the Intent intent.setAction("com.example.aidlserverdemo.MyRemoteService"); Intent finalIntent = IntentUtils.createExplicitFromImplicitIntent(this, intent); // Binding service startService(finalIntent); >>
The second pit is the need to transform the implicit intent into the displayed intent
package com.example.aidlserverdemo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import java.util.List; public class IntentUtils < /*** * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent, * "java.lang.IllegalArgumentException: Service Intent must be explicit" * * If you are using an implicit intent, and know only 1 target would answer this intent, * This method will help you turn the implicit intent into the explicit form. * * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466 * @param context * @param implicitIntent - The original implicit intent * @return Explicit Intent created from the implicit original intent */ public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) < // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); ListresolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) < return null; >// Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; > >
Then turn on the service end, because the client is service-based, it must be turned on.
Copy the IPerson.aidl of the server and execute Build—>Make Module’aidlserverdemo’
1) Create a ServiceConnection object
// instantiate ServiceConnection private ServiceConnection conn = new ServiceConnection() < @Override synchronized public void onServiceConnected(ComponentName name, IBinder service) < Log.d("MainActivity","onServiceConnected()---------->"); // Get IPerson interface iPerson = IPerson.Stub.asInterface(service); Log.d("MainActivity","iperson----------:" + iPerson); > @Override public void onServiceDisconnected(ComponentName name) < Log.d("MainActivity","onServiceDisconnected()---------->"); iPerson = null; > >;
Note that there are also pits here. Package and action must be added. Package is the package name of the server and action is the action of the above service.
Intent intent = new Intent(); //This must be added in 5.0 and above intent.setPackage("com.example.aidlserverdemo"); intent.setAction("com.example.aidlserverdemo.MyRemoteService");//This is the action of the above service bindService(intent, conn, Service.BIND_AUTO_CREATE);
btn.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < try < String msg = iPerson.display(); // Display method call return value Log.d("MainActivity", "msg====-->" + msg); > catch (Exception e) < Log.d("MainActivity", "e====-->" + e); e.printStackTrace(); > > >);
@Override protected void onDestroy() < if (conn != null) < unbindService(conn); >super.onDestroy(); >
5) Operation results:
2020-07-02 09:56:20.461 9151-9151/com.example.aidlclientdemo D/MainActivity: msg====-->name:zzz;age=18
При подготовке материала использовались источники:
https://russianblogs.com/article/7410582993/
https://russianblogs.com/article/48302282907/
https://www.programmersought.com/article/46086338099/