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. В любом случае, надеюсь статья будет полезна хоть кому-то и я потрудился не зря.
Пример
В качестве примера реализуем сервис, который будем увеличивать и уменьшать значение счетчика и возвращать результат в активити, в 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, и выполняющий рутинные операции по упаковке интентов. Также он координирует координирует ответы от сервиса и содержит информацию о командах, выполняющихся в данный момент.
Итак, как это работает:
- 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: Добавил пример реализации сервиса, работающего на пуле потоков
Источник