Статьи

Язык определения интерфейса Android (AIDL) и удаленное обслуживание


В
предыдущей статье мы рассмотрели 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;
		          }
		  };
	}

}

То, что мы сделали, было:

  1. Убедитесь , наша служба расширить службы  и осуществлять ее сек onBind метод, который будет вызываться один раз клиенты посылают запросы (то есть привязка к нашему сервису). Мы используем Bound Service , что означает, что наша служба телефонной книги не будет работать бесконечно в фоновом режиме , а будет работать и оставаться активной только в течение времени, необходимого для обслуживания клиентских запросов.
  2. Метод 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>

Здесь мы предоставляем
интент-фильтр, на который ответит наш сервис. Наш сервис телефонной книги готов. Некоторые вопросы, которые может возникнуть у читателя на этом этапе:

  1. В  предыдущей статье  упоминался Parcel s для IPC. Где именно это здесь вписывается? Где эти предметы, которые можно  продать ?
  2. Должен ли я использовать 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), который будет взаимодействовать с нашим удаленным сервисом.

Из блога Тони