Android BroadcastReceiver или простой метод обратного вызова?

В моих проектах я использую BroadcastReceiver s как обратный вызов из длинного потока (например, уведомляет о завершении загрузки и отправки некоторых данных ответа из рабочего Thread чтобы активность отображала соответствующее сообщение пользователю. ). Чтобы использовать BroadcastReceiver я должен быть осторожным, чтобы регистрировать и отменить регистрацию широковещательного приемника каждый раз, когда я его использую, а также заботиться о том, какие сообщения отправлять esspecialy, когда я использую этот метод для более разных действий (например, загрузка, создание вызовов WebService и т.д..). А также для отправки пользовательских объектов через намерение Broadcast мне также нужно сделать объекты Parcelable .

В отличие от этого подхода, я также видел подход методов обратного вызова, который, по-видимому, проще, чем метод, который я использую. Методы обратного вызова – это простая реализация интерфейсных методов, которые могут быть использованы для достижения такого же эффекта, как передача BroadcastRecaiver в приложении. Этот подход не требует реализации Parcelable для возврата сложных объектов, и он не использует такие ключи, как BroadcastReceiver . Я думаю, что плохая часть заключается в том, что мне нужно проверить объект обратного вызова для нулевого значения, прежде чем я хочу вызвать метод обратного вызова. А также убедиться, что я запускаю код из реализации в потоке пользовательского интерфейса, поэтому я могу обновить интерфейс без ошибок.

Хорошо, надеюсь, вы поняли, что я хотел сказать :).

Теперь вопрос в том, как вы думаете, что метод обратного вызова лучше (легче, чище, быстрее ..), чем подход BroadcastReceiver когда он используется только внутри одного приложения? (Обратите внимание, что я не использую Service Android для фоновой работы … просто AsyncTask и Thread s)

Спасибо!

Solutions Collecting From Web of "Android BroadcastReceiver или простой метод обратного вызова?"

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

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

PRO

  • Это просто и просто реализовать.
  • Вы получаете безопасность типов между компонентами, которые взаимодействуют друг с другом.
  • Вы можете возвращать произвольные объекты.
  • Это упрощает тестирование, поскольку вам нужно только вводить макет-обратный вызов (например, сгенерированный через mockito или что-то подобное) в модульных тестах.

CONTRA

  • Вы должны переключиться на основной поток, чтобы выполнять манипуляции с пользовательским интерфейсом.
  • Вы можете иметь только отношения 1 к 1. Связь 1-в-n (шаблон наблюдателя) не реализуется без дальнейшей работы. В этом случае я предпочел бы механизм Android Observer / Observable .
  • Как вы уже сказали, вам всегда нужно проверить значение null перед вызовом функций обратного вызова, если обратный вызов может быть необязательным.
  • Если ваш компонент должен предложить своего рода API-интерфейс обслуживания с различными сервисными функциями, и вы не хотите иметь интерфейс обратного вызова с несколькими функциями общего вызова, вам необходимо решить, предоставлять ли вы специальный интерфейс обратного вызова для каждой сервисной функции, или же вы Обеспечивают единый интерфейс обратного вызова с множеством функций обратного вызова. В более позднем случае все клиенты обратного вызова, используемые для служебных вызовов вашего API, должны реализовать полный интерфейс обратного вызова, хотя большинство тел метода будет пустым. Вы можете обойти это, реализовав заглушку с пустыми телами и сделав ваш callback-клиент наследованным от этого заглушки, но это невозможно, если он уже наследуется от другого базового класса. Возможно, вы можете использовать какой-то динамический обратный вызов прокси (см. http://developer.android.com/reference/java/lang/reflect/Proxy.html ), но тогда он становится очень сложным, и я думаю о том, чтобы использовать другой механизм.
  • Клиент для вызовов обратного вызова должен распространяться через различные методы / компоненты, если он не доступен напрямую вызывающей стороне службы.

Некоторые моменты, касающиеся BroadcastReceiver -approach:

PRO

  • Вы достигаете рыхлой связи между вашими компонентами.
  • Вы можете иметь отношение 1-к-n (включая 1-к-0).
  • Метод onReceive() всегда выполняется в основном потоке.
  • Вы можете уведомлять компоненты во всем своем приложении, поэтому компонентам связи не нужно «видеть» друг друга.

CONTRA

  • Это очень общий подход, поэтому сортировка и разметка данных, передаваемых Intent является дополнительным источником ошибок.
  • Вы должны сделать действия вашего Intent уникальными (например, добавив имя пакета), если вы хотите устранить корреляции с другими приложениями, поскольку их первоначальная цель – делать трансляции между приложениями.
  • Вы должны управлять BroadcastReceiver-регистрацией и регистрацией. Если вы хотите сделать это более удобным способом, вы можете реализовать пользовательскую аннотацию, чтобы аннотировать свою активность с действиями, которые должны быть зарегистрированы, и реализовать базовый класс Activity , который регистрирует и отменяет регистрацию с помощью IntentFilter s в onResume() или. onPause() .
  • Как вы уже сказали, данные, отправленные с Intent , должны реализовать интерфейс Parcelable , но кроме того, существует строгое ограничение по размеру, и это вызовет проблемы с производительностью, если вы переносите большой объем данных с помощью вашего Intent . См. http://code.google.com/p/android/issues/detail?id=5878 для обсуждения этого вопроса. Поэтому, если вы хотите отправлять изображения, например, вы должны хранить их временно в репозитории и отправлять соответствующий идентификатор или URL-адрес для доступа к изображению получателя вашего Intent который удаляет его из хранилища после использования. Это приводит к дальнейшим проблемам, если есть несколько приемников (когда изображение должно быть удалено из хранилища и кто должен это делать?).
  • Если вы злоупотребляете этим механизмом уведомления, поток управления вашего приложения может быть скрыт, и при отладке вы закончите рисовать графики с последовательностями Intent s, чтобы понять, что вызвало определенную ошибку или почему эта цепочка уведомлений в какой-то момент нарушена.

На мой взгляд, даже мобильное приложение должно иметь базу архитектуры на не менее 2-х уровнях: UI-слой и основной слой (с бизнес-логикой и т. Д.). В общем, длинные задачи выполняются в собственном потоке (возможно, через AsyncTask или HandlerThread при использовании MessageQueue s) внутри основного уровня, и пользовательский интерфейс должен обновляться после завершения этой задачи. В общем случае с обратными вызовами вы достигаете жесткой связи между вашими компонентами, поэтому я предпочел бы использовать этот подход только внутри слоя, а не для связи через границы слоев. Для трансляции сообщений между UI и базовым слоем я бы использовал BroadcastReceiver Approach, который позволяет отделить ваш уровень пользовательского интерфейса от логического уровня.

Я не понимаю, что вы получите, используя BroadcastReceiver в вашем случае. Обратные вызовы или, скорее всего, Handlers могли бы это сделать. BroadcastReceiver хорош, когда вы не знаете, кто подписчики.

Я просто добавлю еще один вариант к другим отличным ответам, которые вы уже получили …

Вам не нужно создавать широковещательный приемник для получения намерений. В вашем файле манифеста Android вы можете зарегистрировать любую активность для получения намерений:

 <activity android:name=".MyActivity"> <intent-filter > <action android:name="intent.you.want.to.receive" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> .... </activity> 

Затем переопределите метод onNewIntent(Intent) в вашей активности, чтобы получить его.

Чтобы отправить Intent, используйте метод Context.startActivity(Intent) . Скорее всего, вы захотите добавить флаг FLAG_ACTIVITY_SINGLE_TOP к своему намерению, чтобы он не создавал новый экземпляр вашей активности, если он уже запущен.

EDIT: Я просто заметил, что вы работаете в одном приложении. Поэтому простой обратный вызов, вероятно, лучше всего. Решение выше работает в одном приложении, но более подходит для разных приложений. Я оставлю это здесь на всякий случай, если это поможет кому-то. Удачи!

Необходимо использовать Broadcastreceivers. Если вам нужно отправлять широковещательные передачи по всем приложениям, в то время как Callbacks (или Handlers, предложенные Алексом) лучше использовать в вашей ситуации.

Если вы хотите использовать другие, кроме этих двух, подумайте об использовании Observer (Interface, включенного в android) и делегирования.

Для делегата, пожалуйста, рассмотрите эту должность.

Надеюсь, это решит вашу проблему

Не знаю, какова цель, но если вы хотите сохранить ту же идею использования намерения и трансляции, и хотите повысить производительность и безопасность, нежели обычные широковещательные радиоприемники, вы можете попробовать эту демонстрацию, доступную в библиотеке поддержки Android:

http://developer.android.com/resources/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.html

Если нет, вы всегда можете использовать asyncTask, службу, обработчики и т. Д. …