В этой статье мы попытаемся описать наш опыт работы с AIDL в Android IPC. Он содержит пример приложения со службой, работающей в отдельном процессе.
Статью следует рассматривать как:
- пример архитектуры приложения с использованием удаленных служб Android и AIDL.
- полезные примеры кода.
- исключительно как дополнение к основной документации по Android Developers (см.
ссылки в конце статьи).
Базовые концепты
Сервис — компонент Android-приложения без пользовательского интерфейса, предназначенный для выполнения ресурсоемких и/или трудоемких операций.Типы Android-сервисов
- Запущенные — сервисы, которые запускаются любым другим компонентом приложения (Activity, BrodcastReceiver, Service) и работают до тех пор, пока не остановятся сами или их кто-то не остановит.
- Связанный (связанный) — сервис, выполняющий роль сервера в архитектуре клиент-сервер.
Этот сервис создается при первом подключении (запросе) от другого компонента приложения.
Служба останавливается, когда последний клиент отключается.
- Служба может быть одновременно запущена и привязана.
Такой сервис способен «жить вечно» и обслуживать запросы клиентов.
Преимущества:
- максимальный размер памяти увеличивается в 2 раза, например 32 МБ/процесс (в зависимости от платформы).
- GC ведет себя менее агрессивно, если у вас есть 2 процесса со снимком N МБ каждый, чем 1 процесс и 2*N МБ.
- стандартные преимущества сервисов Android: фон, независимость от Activity и т.д.
- дополнительные системные ресурсы для низкоуровневой сериализации и десериализации.
- необходимость контроля жизненного цикла процесса.
- еще немного кода.
Файлы AIDL очень похожи на стандартные интерфейсы Java, за исключением:
- Вам необходимо импортировать даже те файлы helpl, которые находятся в одном пакете.
- Ключевое слово oneway в объявлении метода void означает, что метод будет вызываться асинхронно (клиент не ждет его выполнения).
- Вы можете использовать только примитивы, классы String, List и Parcelable, объявленные в других вспомогательных файлах.
Архитектура приложения
Разработанное нами приложение представляет собой галерею для Android, позволяющую просматривать фотографии с карты памяти и сетей обмена фотографиями.Основными задачами сервиса в этом приложении являются: получение метаданных (информации об альбомах, фотографиях, друзьях), отслеживание их обновлений и всего остального, что с ними связано.
Сервис постоянно хранит актуальную информацию и готов в любой момент передать ее основной Activity для отображения.
Ниже приведены ключевые участки кода и процесс создания примитивного сервиса: Для связи между сервисом и Activity используются следующие файлы AIDL: IDataSourceService.aidl – интерфейс сервиса:
IDataSourceServiceListener.aidl — интерфейс для прослушивателей сообщений от сервиса:packagecom.umobisoft.habr.aidlexample.common; import com.umobisoft.habr.aidlexample.common.IDataSourceServiceListener; interfaceIDataSourceService{ voidloadAlbums(in IDataSourceServiceListener listener); … }
package com.umobisoft.habr.aidlexample.common;
import com.umobisoft.habr.aidlexample.common.pojo.Album;
interface IDataSourceServiceListener{
oneway void albumItemLoaded(in Album a);
}
Данные передаются с помощью двух классов, реализующих интерфейс Parcelable, — Album и Photo. Требуется объявление вспомогательных файлов для этих классов.
При преобразовании примитивов ОС в объекты Java используется класс Creator.
Для записи данных используйте метод writeToParcel интерфейса Parcelable: @Override
public void writeToParcel(Parcel out, int flags) {
try{
out.writeLong(id);
out.writeString(name);
out.writeTypedList(photos);
}catch (Exception e) {
Log.e(TAG, "writeToParcel", e);
}
}
Также есть вспомогательный методdescriptionContents, его задача — описать особые случаи/состояния объекта, которые можно использовать при сериализации и десериализации: @Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
Методы чтения данных оказались недостойными включения в интерфейс Parcelable, но стандартной практикой является использование Creator вместе с: private void readFromParcel(Parcel in) {
try{
id = in.readLong();
name = in.readString();
photos.clear();
in.readTypedList(photos, Photo.CREATOR);
}catch (Exception e) {
Log.e(TAG, "readFromParcel", e);
}
}
Действие запускает службу (таким образом, StartedService) в методе onCreate. @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView)findViewById(R.id.album_text);
Intent serviceIntent = newIntent(this, DataSourceService.class);
startService(serviceIntent);
connectToService();
}
На этом же этапе жизненного цикла он подключается к сервису: private void connectToService() {
Intent intent = newIntent(this, DataSourceService.class);
this.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
Процесс подключения к сервису асинхронный; он включает реализацию интерфейса ServiceConnection. При подключении к серверу Activity регистрируется в службе в качестве прослушивателя сообщений с использованием реализации IDataSourceServiceListener.Stub: private ServiceConnection serviceConnection = newServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "Service connection established");
serviceApi = IDataSourceService.Stub.asInterface(service);
try {
mainListener = newIDataSourceServiceListener.Stub() {
@Override
publicvoidalbumItemLoaded(final Album a) throwsRemoteException {
mToastHandler.post(new Thread(){
publicvoid run(){
Toast.makeText(HabrahabrAIDLExampleActivity.this, a.toString(), Toast.LENGTH_LONG).
show();
textView.setText(a.toString());
}
});
}
};
serviceApi.loadAlbums(mainListener);
} catch (RemoteException e) {
Log.e(TAG, "loadAlbums", e);
}
}
@Override
publicvoidonServiceDisconnected(ComponentName name) {
Log.i(TAG, "Service connection closed");
serviceApi = null;
connectToService();
}
};
Если во время работы StartedService объем свободной памяти уменьшится до определенного порога, система может закрыть службу без предупреждения.
После этого система должна перезапустить службу.
Таким образом, в методе onServiceDisconnected мы снова инициализируем соединение с сервисом.
Надеюсь, выложенные исходные тексты помогут разработчикам познакомиться с AIDL. Архив с полным примером здесь .
Основное приложение доступно для ознакомления по адресу Android Market .
Официальная документация по Android Developers: Услуги: Developer.android.com/guide/topics/fundamentals/services.html АИДЛ: Developer.android.com/guide/developing/tools/aidl.html Теги: #Android #AIDL #IPC #Разработка Android
-
Если Seagate Запылится...
19 Oct, 24 -
Разработка Soap-Сервиса На Платформе Wso2.
19 Oct, 24 -
Что Такое Информационный Объект
19 Oct, 24 -
Сколько Времени Люди Проводят В Сети?
19 Oct, 24