Android взаимодействие между activity

Android взаимодействие между activity

Мы уже работали над созданием перехода между двумя Activity. Сегодняшний урок довольно похож, но имеет некоторое усложнение — мы будем не просто переходить с одного Activity на другое, но и передавать между ними текстовые данные.

Суть приложения будет в том, что в одном окне будет две формы EditView для заполнения текстом и кнопка Button перехода на другое окно, а в другом — два элемента TextView, которые будут отображать текст, который был введен в EditView в первой Activity и кнопка возвращения назад.

Создаем новый проект с Blank Activity, все названия я оставлю по умолчанию.

Для начала настроим интерфейс первого Activity. Открываем файл activity_main.xml. Мы добавим сюда 2 элемента EditText для ввода текста и кнопку Button:

Все, внешний вид первого Activity готов:

Теперь нам нужно создать новый Activity. В папке Java/имя_вашего_приложения нашего приложения создаем новый Java Class. Клик правой кнопкой мышки по указанной папке New — Java Class:

Зададим ему имя Second. Проследите, чтобы созданный класс Second.java находился в одной папке с MainActivity.java :

Для этого класса нужно создать соответствующий layout — файл, который будет отвечать за его внешний вид (интерфейс). В папке res/layout создаем (правый клик по папке layout — New — Layout resourse file) файл по имени second.

Сразу настроим внешний вид второго Activity. Открываем файл созданный second.xml и добавляем 2 элемента TextView и кнопку Button:

Внешне это выглядит так:

В файле activity_main.xml мы создавали кнопку «Передать» и создали для нее метод нажатия (подчеркнуто):

Чтобы описать процесс нажатия, нужно добавить метод обработки нажатия в MainActivity.java. Для этого ставим курсор на слово «Send» в коде кнопки и жмем комбинацию Alt+Enter и выбираем первую строку Create ‘Send(View)’ in ‘MainActivity’.

Переходим к редактированию файла MainActivity.java . Объявляем используемые переменные, привязываем их к созданным элементам интерфейса, с оздаем с помощью класса Intent переход на Second.java, а также настраиваем получение текстовых данных с элементов EditText для передачи в Second.java :

Создадим метод для обработки нажатия кнопки «Назад» в файле second.xml. Делаем все аналогично кнопке «Передать» (курсор на «Back» — Alt+Enter — Enter):

Теперь переходим к редактированию файла Second.java. Для начала нужно привязать его к second.xml интерфейсу:

Теперь объявляем объекты, привязываем их к созданным в файле разметки интерфейса, настраиваем строковые ресурсы с полученных с первого Activity данных и выводим на экран, а также для обработчика нажатия клавиши пишем код перехода обратно:

Остается только объявить о созданном Second.java в файле манифеста. Открываем AndroidManifest.xml и добавим туда между тегами :

Вот и все, приложение готово, можно переходить к тестированию.

Источник

Коммуникация между Activity и Service

Нам нужно передавать данные из активити в сервис и обратно. Как нам это сделать? Для решения нашей задачи у нас уже есть все необходимое. Все что нужно — это привязать сервис к ативити, используя bindService, передать нужные параметры и немного магии в виде использования классов Message. А магия заключается в том, чтобы использовать переменные экземпляра Message и в частности, replyTo. Данная переменная нужна нам, чтобы мы могли обратиться к экземпляру Messanger сервиса из активити и в сервисе к экземпляру Messanger-а активити. На самом деле, не так уж и просто. По крайней мере для моего не самого одаренного ума. Отчасти, я улучшаю документацию, которая уже есть — Services. Улучшаю тем, что добавляю связь с активити, передавая данные туда-обратно, чего нет в документации. Также, есть хороший пример на StackOverflow. В любом случае, надеюсь статья будет полезна хоть кому-то и я потрудился не зря.

Читайте также:  Как посмотреть недавно добавленные контакты android

Пример

В качестве примера реализуем сервис, который будем увеличивать и уменьшать значение счетчика и возвращать результат в активити, в TextView. Код макета опущу, ибо там две кнопки и текстовое поле — все просто.

Реализация

Приведу полностью код активити:

Поясню. При создании активити мы сразу привязываемся к сервису, реализуя интерфейс ServiceConnection и в нем оправляем сообщение сервису «установить значение счетчика», передавая ноль и создавая toServiceMessanger, передавая в конструктор интерфейс IBinder. Кстати, в сервисе обязательно нужно вернуть этот экемпляр, иначе будет NPE. С помощью этого класса мы и отправляем сообщения сервису. И вот она магия — в переменную replyTo мы сохраняем наш другой экземпляр Messenger — тот который получает ответ от сервера и именно через него и будет осуществляться связь с активити.

Для получения сообщения от сервиса используем свой Handler и просто ищем нужные нам переменные и делаем по ним действия. По кликам на кнопки(методы countIncrClick, countDecrClick) отправляем запросы к сервису, указывая нужное действие в переменной msg.what.

Далее, полный код сервиса:

Все по аналогии с логикой в активити. Даже не знаю, нужно ли что-то пояснять. Единственный момент — это то, что я сразу отправляю запрос обратно в активити в handleMessage, используя для этого волшебную переменную replyTo и вытаскивая выше нужный Messenger. И второй момент о котором я уже говорил — это:

без которого все упадет. Именно данный экземпляр интерфейса и будет передан в ServiceConnection

Заключение

Вцелом все. Такой вот надуманный пример взаимодействия активити и сервиса. Мне кажется, довольно таки нетривиальное взаимодействие, хотя кому-то может показаться иначе.

Код проекта есть на Bitbucket

Вопросы, уточнения и прочее в личку. Могут быть неточности по поводу каких-либо аспектов, поэтому смело пишите и поправляйте.
Надеюсь, пост был полезен хабраюзерам.

Источник

Урок 24. Activity Lifecycle — взаимодействие двух активити | Уроки Android Studio

В этом уроке продолжаем работать с методами жизненного цикла активити, создаем второе Activity в приложении и наблюдаем смену состояний активити при переходе между ними

Скачать исходный код проекта: link

Группа взаимопомощи Вконтакте для начинающих ANDROID разработчиков и программистов: link
Скачать видеоуроки: link
Поддержите наш проект: link
#fandroid.info #AndroidStudio #startandroid

Ответ на вопрос Макса Сергеева (лучше поздно чем никогда? ) ), переход по стрелочке назад организовывается через указание родительской связи при создании нового активити, либо вручную при добавлении свойства «android:parentActivityName» у соответствующего активити в AndroidManifest.xml

Интересно тут вот что.
Если мы возвращаемся назад на предыдущее активити стрелкой в шапке, то оно уничтожается и создаётся заново .
«Activity 2 create!
onStart — Activity 2 становится видимым!
onResume — Activity 2 получает фокус!
onStop — Main Activity остановлено!
onPause — Activity 2 приостановлено!
Activity 3 create!
onStart — Activity 3 становится видимым!
onResume — Activity 3 получает фокус!
onStop — Activity 2 остановлено!
onPause — Activity 3 приостановлено!
onDestroy — Activity 2 уничтожено!
Activity 2 create!
onStart — Activity 2 становится видимым!
onResume — Activity 2 получает фокус!
onStop — Activity 3 остановлено!
onDestroy — Activity 3 уничтожено!»

Читайте также:  Калибровка экрана планшет андроид

А если мы возвращаемся через кнопку назад на телефоне то оно восстанавливается.
«onPause — Activity 2 приостановлено!
Activity 3 create!
onStart — Activity 3 становится видимым!
onResume — Activity 3 получает фокус!
onStop — Activity 2 остановлено!
onPause — Activity 3 приостановлено!
onRestart — Activity 2 перезапускается!
onStart — Activity 2 становится видимым!
onResume — Activity 2 получает фокус!
onStop — Activity 3 остановлено!
onDestroy — Activity 3 уничтожено!»

Хотя может быть это всем известная вещь и я ещё не дошел до той лекции где это описывается.

Источник

Организация архитектуры взаимодействия Activity и Service

Сегодня я решил поведать Вам мой способ организации activity-service interaction в Android приложениях. Мотивирован топик тем, что достаточно часто можно встретить приложения, в которых, скажем, поход на сервер организовывается внутри активити в AsyncTask. При этом часто встречается верная мысль, что это надо делать в сервисах, но нигде в оф. документации нет ни слова об организации правильной архитектуры двустороннего взаимодействия между ними.

Поэтому я методом проб и ошибок пришел к архитектуре, лично для меня покрывающей все необходимые вопросы.

Об этом методе я буду рассказывать далее.

С высоты птичьего полета

Давайте сначала рассмотрим высокоуровневую картину предлагаемой архитектуры.

Далее в статье я буду использовать два термина — управляемая и неуправляемая обратная связь. Это неофициальные термины, но я их буду использовать, т. к. они мне нравятся. Управляемые — это уведомления, осуществляемые платформой Android для нас (ContentProvider + ContentObserver система). Для того, чтобы UI получал управляемые уведомления нам ничего не нужно, кроме корректно реализованного провайдера.

Гораздо интересней — как реализованы неуправляемые уведомления, т. е. те, которые осуществляются при помощи нашей системы событий. Ведь не всегда выполнение какой-то операции в сервисе сопряжено с записью в провайдер, поэтому нам нужен свой механизм уведомления клиента о том, что сервис завершил работу.

Итак, данная архитектура подразумевает наличие четырех основных компонентов системы:

  • Activity, выполняющую стандартную роль отображения интерфейса
  • Service — сервис, выполняющий тяжелую работу в background потоке
  • ServiceHelper — наш компонент, который будет склеивать нашу активити и сервис и предоставлять неуправляемые уведомления
  • ContentProvider — необязательный, в зависимости от вашего UI компонент, который будет помогать осуществлять управляемые уведомления.

Сервис

Наш сервис выполняет роль command processor’а.

Каждый входящий интент несет в extras:

  • Действие, которое необходимо выполнить
  • Аргументы, определяемые командой
  • ResultReceiver

Сервис смотрит на переданный action, сопоставляет ему команду, которую нужно выполнить, и передает аргументы и ResultReceiver команде.

Самый простой вариант реализации сервиса:

Здесь в большом блоке if просто ищется нужная команда. Понятное дело, здесь можно как угодно загнаться, чтобы избежать ифа: держать Map action-handler, сделать фабрику, использовать IoC и т. п., но это выходит за рамки статьи.

Handler

Обработчики инкапсулируют в себе выполняемую процедуру. У меня они образуют определенную иерархию, где базовый класс выглядит как:

следующим уровнем иерархии я реализовал базовую команду, выполняющую подготовку http запроса, но это, опять же выходит за рамки статьи. В целом, Вы наследуетесь от базовой команды и реализуете doExecute, в котором при необходимости вызываете sendUpdate метод, передаете код (успех/ошибка) и Bundle с данными.

ServiceHelper

ServiceHelper — это промежуточный слой между UI и сервисом, упрощающий вызовы к сервису для UI, и выполняющий рутинные операции по упаковке интентов. Также он координирует координирует ответы от сервиса и содержит информацию о командах, выполняющихся в данный момент.

Читайте также:  Installed packages android sdk

Итак, как это работает:

  • UI вызывает метод хелпера, хелпер возвращает ID запроса
  • Хелпер запоминает ID запроса
  • Собирает Intent, в который вкладывет ResultReceiver и отправляет сервису
  • когда сервис завершает операцию, в onReceiveResult оповещаются все слушающие UI компоненты

Давайте посмотрим на код:

Сервис хелпер держит список подписчиков в массиве, именно на этот список будут рассылаться уведомления по работе команд.

это — общий метод по созданию нашего интента, который мы зашлем сервису.
Более интересным местом является pendingActivities — это регистр всех выполняющихся на данный момент задач на сервисе. Поскольку при вызове метода ServiceHelper мы получаем id, мы всегда можем узнать, выполняется команда или нет. Подробней об этом — чуть далее в статье.

Теперь пример public метода, который будет выполнять какое-то действие на нашем сервисе:

и вот таких методов, торчащих наружу будет ровно столько, сколько команд поддерживает ваш сервис.

Activity

Итак, как я уже сказал, у нас есть интерфейс:

Я считаю, что удобно в базовой абстрактной активити реализовывать сей интерфейс. Тогда в конкретных активити Вам надо будет всего лишь переопределить метод onServiceCallback для получения уведомлений, что очень похоже на стандартные callback методы в activity, т. е. грациозно вписывается в Ваш клиентский код.

Обратите внимание, как активити подписывается и отписывается от ServiceHelper в своих методах onResume/onPause. Это позволяет избегать проблем при пересоздании активити, например, при повороте экрана, или сворачивании приложения.

Давайте рассмотрим, что нам приходит в метод onServiceCallback:

  • requestId — уникальный идентификатор, сгенерированный при отправке запроса
  • requestIntent — оригинальный интент, который мы послали
  • resultCode — код результата выполнения
  • resultData — данные

Теперь, у нас есть все необходимое, чтобы в нашей activity мы всегда могли получить уведомление от нашего сервиса без кучи boilerplate кода.
Более того, что мне кажется очень полезным — мы можем идентифицировать как конкретный запрос по ID, так и все запросы одного типа по action, что дает нам огромную гибкость.

Также, имея ID запроса, мы можем выполнять отложенную проверку. Представим последовательность:

  • пользователь запустил действие, запустилась крутилка
  • закрыл приложение на 2 минуты
  • действие уже выполнилось
  • пользователь открыл снова
  • тут мы проверяем в onResume, выполнилась ли операция, и убираем крутилку

т. е., просто вызываем getServiceHelper().isPending(requestId), если нам это нужно.

Заключение

Вот, пожалуй, и все.

Сразу скажу, что я не претендую на универсальность данной архитектуры или на какую-то ее уникальность. Она была медленно выведена мной путем проб и ошибок, просмотров различных материалов и т. п. Но, пока, все мои нужды в настоящих коммерческих проектах она покрывает на 100%.

Более того, если чего-от не хватает — ее можно легко расширить. Из очевидного:

  • добавить помимо success и failure код progress, тогда с сервиса можно будет передавать информацию о прогрессе задачи и отображать ее в, скажем ProgressBar
  • прикрутить код по прерыванию выполняемой задачи
  • и т. п.

Еще одна деталь, у меня код ServiceHelper не синхронизирован, т. к. подразумевается, что его методы будут вызываться в UI thread всегда. Если у Вас это не так, то необходимо добавить синхронизацию при любом изменении состояния ServiceHelper.

В общем, спасибо за внимание, надеюсь, кому-то поможет. Готов отвечать на Ваши вопросы и замечания в комментах.

UPD: Выложил маленький sandbox примерчик, иллюстрирующий архитектуру на GitHub: https://github.com/TheHiddenDuck/android-service-arch

UPD 2: Добавил пример реализации сервиса, работающего на пуле потоков

Источник

Оцените статью