#android #architecture #android-service
#Android #архитектура #android-сервис
Вопрос:
Сначала я прошу прощения за мой английский, который не так хорош :).
Я столкнулся с проблемой разработки своего приложения.
Это общая схема архитектуры моего решения.
http://i.stack.imgur.com/ooTmE.png
Чтобы быть быстрым, приложение должно декодировать голый код, но двумя возможными способами:
- использование внешнего устройства (конструктор предоставляет sdk, содержащий службу Android для связи с устройством),
- используйте камеру мобильного телефона, используя библиотеку Zxing, с помощью которой можно управлять ею намеренно.
Цель моего собственного сервиса — управлять некоторым бизнес-кодом и сделать прозрачным выбор инструмента для пользователя.
Я считал, что это хорошее решение, но я хотел его реализовать, и у меня были разные проблемы.
Моя главная проблема в том, что я не могу выполнить startActivityForResult внутри службы.
Есть ли у кого-нибудь какие-либо предложения по моей проблеме, будь то изменение архитектуры или решение основной проблемы?
@Laurent’: Вы абсолютно правы, мой сервис действует как адаптер API.
Я постараюсь сделать ожидаемое поведение более понятным.
У меня есть приложение, которое должно распознавать (реальные) объекты, на которых есть QR-коды сверху. Это действие распознавания будет выполняться пользователем несколько раз в течение срока службы приложения.
Пользователь выбирает запуск распознавания, нажав на кнопку (или иным образом, но он знает, что распознавание начнется). Таким образом, уведомление не требуется.
Дело в том, что он не выбирает способ распознавания. Именно поэтому, как вы сказали, я реализую адаптер.
Адаптер выбирает между :
Камера мобильного или внешнего устройства. Первое — это действие, исходящее из библиотеки Zxing. Вторая — это служба, которая управляет внешним устройством. Эта служба предоставляет интерфейс для получения результата.
Еще одна вещь, мне нужно, чтобы вся моя реализация (адаптер и со) могла быть повторно использована другими приложениями, которым также потребуется распознавание.
Итак, моя мысль заключалась в том, чтобы реализовать сервис в качестве адаптера, чтобы ответить на мои два условия (сделать выбор прозрачным для пользователя — и сделать распознавание доступным для других приложений).
Надеюсь, вы понимаете мою проблему.
Ответ №1:
Учитывая вашу архитектуру, вы MyOwnService
должны действовать как адаптер API: он должен предоставлять унифицированный API сканирования и прозрачно учитывать специфику каждой внешней службы.
Ваше ожидаемое поведение недостаточно ясно, чтобы обеспечить решение, соответствующее вашим потребностям, но вот несколько замечаний, которые могут помочь.
Пассивное сканирование:
- Даже если есть некоторые обходные пути: никакая активность не должна запускаться из службы (не напрямую). Никогда. Плохо. Сервисы — это фоновый материал, максимум, что им будет разрешено, — это подсказать пользователям
Notifications
(это пункт 2 отличного ответа Джастина).
Как следствие, нет ничего похожего на «всплывающие действия» (и это хорошо!). Если вам нужно постоянно сканировать штрих-коды, даже когда ваша активность не выполняется, то единственный способ предупредить пользователей — использовать уведомление в строке состояния.
Активное сканирование:
- Внутри вашей собственной активности вы можете
bind
подключиться к своей службе-оболочке и заставить ее начать сканирование на наличие строк кода. Когда он находит его, он относится кmessage
вашей активности. Ваша активностьmessage handler
имеет полный доступ к пользовательскому интерфейсу, чтобы информировать пользователя о ваших результатах.
Вы выбрали активное сканирование при редактировании, поэтому ваша проблема заключается в том, чтобы найти способ, чтобы ваша служба активно уведомляла ваше основное приложение (то, которое запустило активное сканирование) об успешном сканировании нового элемента.
Вы НЕ делаете этого, запуская новое действие (помните: это плохо), но вы можете bind
использовать службу и / или использовать Messages
между службой-оболочкой и приложением.
Я советую вам потратить время на чтение (и больше времени на понимание) этой статьи для разработчиков Android о BoundServices и особенно о части Messengers
.
Полный пример двухстороннего обмена сообщениями между службой и действием можно найти в следующих примерах Android: Service amp; Activity
Внимание: разработка надежных, полноценных сервисов на основе AIDL — сложная задача.
Комментарии:
1. Вы полностью правы, мой сервис действует как адаптер API. Я постараюсь сделать ожидаемое поведение более понятным. У меня есть приложение, которое должно распознавать (реальные) объекты, на которых есть QR-коды сверху. Это действие распознавания будет выполняться пользователем несколько раз в течение срока службы приложения. Пользователь выбирает запуск распознавания, нажав на кнопку (или иным образом, но он знает, что распознавание начнется). Таким образом, уведомление не требуется. Дело в том, что он не выбирает способ распознавания. Именно поэтому, как вы сказали, я реализую адаптер. [… СЛЕДУЮЩИЙ КОММЕНТАРИЙ]
2. [ПРЕДЫДУЩИЙ КОММЕНТАРИЙ …] Адаптер выбирает между: камерой, мобильным или внешним устройством. Первое — это действие, исходящее из библиотеки Zxing. Вторая — это служба, которая управляет внешним устройством. Эта служба предоставляет интерфейс для получения результата. Еще одна вещь, мне нужно, чтобы вся моя реализация (адаптер и со) могла быть повторно использована другими приложениями, которым также потребуется распознавание. Итак, моя мысль заключалась в том, чтобы реализовать сервис в качестве адаптера, чтобы ответить на мои два условия (сделать выбор прозрачным для пользователя — и сделать распознавание доступным для других приложений). Я надеюсь, что я более понятен
3. спасибо, я прочитаю статью о bounded service . Просто я уже привязываю MainActivity к сервису для управления некоторыми частями сервиса, такими как startScan или getDeviceStatus. Но я хотел бы, чтобы вся бизнес-часть распознавания внутри службы хорошо отделяла основное приложение от части распознавания. Но это кажется сложным. Я собираюсь прочитать статью и вернуться после 🙂 Спасибо миллион за ваше время и интерес к моей проблеме.
Ответ №2:
Вы могли бы решить эту проблему двумя способами.
1) Попросите MyOwnService выполнить обратный вызов в MainActivity, сообщив ему о запуске вашей ScanActivity. — Это лучший подход, если задача MyOwnService будет выполняться только во время выполнения MainActivity и если пользователь ожидает, что ScanActivity появится автоматически.
2) Попросите MyOwnService создать уведомление, которое позволит пользователю получить доступ к ScanActivity. — Это лучший подход, если задача MyOwnService может выполняться дольше, чем срок службы MainActivity . Таким образом, вы можете ненавязчиво сообщить пользователю, что он может захотеть получить доступ к ScanActivity.
Комментарии:
1. Мой выбор был бы в пользу первых способов, потому что служба не должна отправлять уведомления вне жизненного цикла моей MainActivity. Но дело в том, что я нахожу немного странным, что основное действие запускает службу, а затем служба, если она выбирает мобильную камеру для сканирования, должна выполнить обратный вызов для основного действия… На мой взгляд, я ожидал, что весь бизнес-код останется внутри службы… Я не уверен, достаточно ли я понятен
2. Я ожидал, что весь код, касающийся сканирования и распознавания, останется внутри сервиса и других приложений, которые ему нужны…
3. Я могу понять вашу озабоченность, но вы также говорите, что ваш бизнес-код включает в себя манипулирование пользовательским интерфейсом, чего не должно быть. Бизнес-код должен отправлять событие обратно в пользовательский интерфейс, чтобы он мог решить, как лучше всего вызвать ScanActivity. По крайней мере, я так на это смотрю.
4. Привет, Джастин, мой бизнес-код не изменяет мой пользовательский интерфейс, а если и изменяет, то с помощью обратного вызова благодаря интерфейсу моего собственного сервиса. (С использованием bindService()). Проблема заключается в запуске действия, которое использует камеру для сканирования. Как я пытался объяснить выше. Я хотел бы использовать сервер только как АДАПТЕР и сделать этот адаптер доступным в течение всего срока службы приложения и доступным для других приложений. Но, возможно, выбор службы не является хорошим выбором… Честно говоря, я запутался в архитектуре Android..
5. Я имел в виду, что, когда ваша служба запускает действие, она изменяет пользовательский интерфейс, вызывая его появление. Если вы хотите изолировать MainActivity от того, какую ScanActivity вы хотите запустить, я бы предложил передать намерение в обратном вызове обратно в основное действие. Таким образом, все, что нужно сделать для основного действия, это вызвать startActivity, используя намерение, предоставленное вашей службой. Это должно достаточно разделять вещи.
Ответ №3:
Итак, наконец, я изменил свою архитектуру.
Я выбираю удалить myOwnService и создать промежуточное действие, которое будет моим адаптером API.
Это действие будет иметь dialog.theme, чтобы выглядеть как диалоговое окно, указывающее, что выполняется распознавание.
Если для распознавания используется внешнее устройство, это действие останется на переднем плане, в противном случае начнется действие камеры (управляемое промежуточным действием).
Благодаря этому я могу управлять своим результатом из промежуточного действия и не имею странной архитектуры Android, сохраняя свой бизнес-код для распознавания за пределами моего основного приложения.
Сервис не был хорошим выбором.
Большое спасибо за вашу помощь и ваше время.