В
предыдущей статье мы рассмотрели Android
Inter Process Communication (IPC) и представили контейнеры для быстрой IPC под названием
Parcel s.
Мы также упомянули, что по соображениям безопасности каждое приложение Android запускается в своем собственном процессе и обычно не может получить доступ к данным другого приложения, работающего в другом процессе. Таким образом, механизмы пересечения границ процесса должны проходить через четко определенные каналы. Чтобы позволить одному приложению взаимодействовать с другим, запущенным в другом процессе, Android обеспечивает реализацию IPC через язык определения интерфейса Android (AIDL) .
Фактический механизм AIDL должен быть знаком разработчикам Java: вы предоставляете интерфейс, и инструмент (инструмент aidl ) будет генерировать необходимую систему, чтобы другие приложения (клиенты) могли взаимодействовать с вашим приложением (службой) через границы процесса. , Время для конкретного примера.
Допустим, мы хотим внедрить службу телефонной книги, чтобы другие приложения Android могли искать по имени и получать список соответствующих телефонных номеров. Мы начнем с создания простого интерфейса для выражения этой возможности, написав файл IPhoneBookService.aidl в нашем каталоге исходных текстов :
package com.ts.phonebook.service; /* PhoneBook remote service, provides a list of matching phone numbers given a person's name*/ interface IPhoneBookService{ List<String> lookUpPhone(String name); }
Как сохранить эту .aidl файл в нашем Android проект в Eclipse, Android, aidl инструмент автоматически генерирует соответствующий IPhoneBookService.java стаб — файл в каталоге «ген» нашего проекта. Следующим шагом для нас будет реализация нашего сервиса, и мы создадим конкретный класс PhoneBookService . Вот код скелета:
package com.ts.phonebook.service; import java.util.ArrayList; import java.util.List; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class PhoneBookService extends Service{ @Override public IBinder onBind(Intent intent) { return new IPhoneBookService.Stub() { //helper method generated by Android public List<String> lookUp(String name) throws RemoteException { // our service implementation List<String> phoneList = new ArrayList<String>(); // populate list above by looking up by name in our phone book database //... code here // return list of phone numbers corresponding to name parameter return phoneList; } }; } }
То, что мы сделали, было:
- Убедитесь , наша служба расширить службы и осуществлять ее сек onBind метод, который будет вызываться один раз клиенты посылают запросы (то есть привязка к нашему сервису). Мы используем Bound Service , что означает, что наша служба телефонной книги не будет работать бесконечно в фоновом режиме , а будет работать и оставаться активной только в течение времени, необходимого для обслуживания клиентских запросов.
- Метод onBind возвращает IBinder , представляющий удаленную реализацию нашего сервиса. Ранее мы видели, что Android сгенерировал заглушку gen / IPhoneBookService.java , поэтому мы используем этот сгенерированный вспомогательный метод, чтобы вернуть клиенту конкретную заглушку, содержащую реализацию нашего метода сервиса.
Наши клиентские приложения теперь могут вызывать наш метод lookUp, чтобы получить список из 0, 1 или более телефонных номеров в нашей базе данных, соответствующих имени, которое они указали. Мы внедрили наш сервис, но нам все еще нужно зарегистрировать его в файле AndroidManifest.xml нашего приложения:
<application...> ... <service android:name=".PhoneBookService"> <intent-filter> <action android:name="com.ts.phonebook.service.IPhoneBookService" /> </intent-filter> </service> ... </application>
Здесь мы предоставляем
интент-фильтр, на который ответит наш сервис. Наш сервис телефонной книги готов. Некоторые вопросы, которые может возникнуть у читателя на этом этапе:
- В предыдущей статье упоминался Parcel s для IPC. Где именно это здесь вписывается? Где эти предметы, которые можно продать ?
- Должен ли я использовать AIDL для IPC или есть другие альтернативы?
Здесь, наш очень простой удаленный сервис просто возвращает список из Струнных объектов. Типы строк поддерживаются AIDL «из коробки», также поддерживается список поддерживаемых элементов. Но предположим, что мы хотим реализовать более сложный удаленный сервис, который возвращает не только номера телефонов, но и целый набор пользовательских данных, таких как возраст, род занятий, пол, зарплата и т. Д. … Если мы хотим вернуть пользовательский объект User с все эти атрибуты для наших абонентов, наш класс User должен быть Parcelable.
Поэтому мы бы написали класс User, реализующий интерфейс Parcelable, так же, как мы это делали в предыдущей статье:
package com.ts.userdata.service; import android.os.Parcel; import android.os.Parcelable; public class User implements Parcelable { // code here @see previous article }
А также напишите файл user.aidl, содержащий всего две строки:
package com.ts.userdata.service; parcelable User;
Почему второй файл .adl ? Контракт AIDL требует, чтобы мы создали отдельный файл .aidl для каждого класса, объявленного как Parcelable, который мы хотим использовать в нашем сервисе.
Вот и все. Мы объявили User как Parcelable и реализовали его таким образом, чтобы его можно было маршалировать / разбивать через границы процессов. Вот как будет выглядеть наш сервисный интерфейс AIDL в IUserDataService.aidl :
package com.ts.userdata.service; import com.ts.userdata.service.User; // needed here /* User data remote service, provides all available info about an individual given its id number */ interface IUserDataService{ User lookUpUser(long userid); }
Реальная реализация снова будет использовать сгенерированную S tub (), но вернет тип User вместо List of String типов. Обратите внимание на утверждение импорта . В файле IUserDataService.aidl нам все еще нужно импортировать наш файл определения User .aidl, даже если он находится в том же пакете.
Что касается второго вопроса, ответ — да, мы можем сделать IPC без AIDL , используя Messenger . В этом случае клиент не будет вызывать методы службы, а вместо этого отправлять ей сообщения.
Мы рассмотрим альтернативу Messenger в следующей статье. Мы также еще не говорили о клиентской стороне, то есть создали клиента в другом приложении (в отдельном проекте Android), который будет взаимодействовать с нашим удаленным сервисом.
Из блога Тони