Более эффективный способ обновления пользовательского интерфейса от службы, чем намерения?

В настоящее время у меня есть Служба на Android, которая является образцом VOIP-клиента, поэтому она прослушивает сообщения SIP и, если она ее получает, запускает экран Activity с компонентами пользовательского интерфейса.

Затем следующие сообщения SIP определяют, что должно отображаться на экране. Например, если в его входящем вызове появится ответ «Ответ» или «Отклонить» или исходящий вызов, он отобразит экран набора номера.

В тот момент, когда я использую Intents, чтобы сообщить Activity, какое состояние оно должно отображать.

Примером может служить следующее:


Intent i = new Intent(); i.setAction(SIPEngine.SIP_TRYING_INTENT); i.putExtra("com.net.INCOMING", true); sendBroadcast(i); Intent x = new Intent(); x.setAction(CallManager.SIP_INCOMING_CALL_INTENT); sendBroadcast(x); Log.d("INTENT SENT", "INTENT SENT INCOMING CALL AFTER PROCESSINVITE"); 

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

Пример кода:


  SipCallListener = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(SIPEngine.SIP_RINGING_INTENT.equals(action)){ Log.d("cda ", "Got RINGING action SIPENGINE"); ringingSetup(); } if(CallManager.SIP_INCOMING_CALL_INTENT.equals(action)){ Log.d("cda ", "Got PHONE RINGING action"); incomingCallSetup(); } } }; IntentFilter filter = new IntentFilter(CallManager.SIP_INCOMING_CALL_INTENT); filter.addAction(CallManager.SIP_RINGING_CALL_INTENT); registerReceiver(SipCallListener, filter); 

Это работает, однако кажется, что он не очень эффективен, Intents получат широковещательную систему, и намерения, которые должны срабатывать для разных состояний, похоже, что они могут стать неэффективными, чем больше я должен включать, но и добавить сложность.

Поэтому мне было интересно, есть ли другой более эффективный и чистый способ сделать это?

Есть ли способ поддерживать Intents вещание только внутри приложения?

Будет ли обратная связь лучшей идеей? Если да, то почему и каким образом они должны быть реализованы?

ОБНОВЛЕНИЕ 2015:

Этот вопрос / ответ по-прежнему получает немного активности, но он старше 5 лет, и все изменилось совсем немного. 5 лет назад ответ был следующим: как бы я справился с этим. Позже я написал очень легкое решение для инъекций зависимостей, которое я использовал некоторое время (что я упомянул в комментариях). В настоящее время я бы ответил на этот вопрос, используя Dagger и RxAndroid. Кинжал, чтобы ввести класс «посредника» и в Службу, и во все действия, которые должны быть уведомлены, Служба будет подталкивать обновление статуса к классу посредника, а класс посредника будет показывать наблюдаемые для того, чтобы действия потребляли обновление статуса ( Вместо приемника вещания OP).

Оригинальный ответ

Я обычно подклассифицирую приложение и позволяю моей связи в приложении проходить через этот класс (или иметь посредника, принадлежащего Приложению, выполнять работу … независимо от того, что приложение является точкой входа для связи службы). У меня есть связанная служба, которая также нуждается в обновлении интерфейса (намного проще, чем ваша, но та же идея), и в основном он сообщает приложению о своем новом состоянии, и приложение может затем передать эту информацию так или иначе Активная деятельность. Вы также можете поддерживать указатель на текущее активное действие (если его несколько) и принимать решения о том, нужно ли просто обновлять текущую деятельность, транслировать намерение запуска другого действия, игнорировать сообщение и т. Д. Я бы Также подкласс Activity и ваш новый базовый класс активности сообщите Application, что он в настоящее время является активным в onResume и что он приостанавливается inPause (для случаев, когда ваша служба работает в фоновом режиме и все действия приостановлены).

РЕДАКТИРОВАТЬ:

В ответ на комментарий, здесь более подробно.

В настоящее время ваше приложение состоит из классов, производных от производных и служб, по большей части. По сути, вы получаете функциональность из экземпляра класса android.app.Application. Это объявлено в вашем манифесте (по умолчанию) со следующей строкой:

 <application android:icon="@drawable/icon" android:label="@string/app_name"> 

Элемент приложения в вашем манифесте не использует атрибут android: name, поэтому он просто создает экземпляр класса android.app.Application по умолчанию для представления вашего глобального контекста приложения.

В моих приложениях я создаю подкласс приложения (ApplicationEx, например), и я расскажу в своем приложении через манифест, что это класс для создания экземпляра в качестве глобального контекста приложения. Например:

 <application android:name="com.mycompany.myapp.app.ApplicationEx" android:icon="@drawable/app_icon" android:label="@string/app_name"> 

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

Вторая часть этого заключается в том, что вместо получения моих сервисов и действий из Сервиса и Activity я создаю подкласс каждого из них с методом getAppContext, который возвращает возвращаемое значение getApplicationContext (которое существует уже в обоих этих классах, потому что они происходят из контекста ) К моему классу ApplicationEx.

Так……..

Все сказанное добавляет свойство CurrentActivity к классу ApplicationEx типа Activity (или ActivityBase, если вы подклассифицируете его так же, как и я). В методе onResume ActivityBase вы переходите к ApplicationEx, чтобы установить CurrentActivity для этой активности. Теперь вы можете выставлять методы на ApplicationEx для передачи информации непосредственно в текущую деятельность вместо того, чтобы полагаться на механизмы Intent.

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

Вы можете отправлять трансляции намерения только к своему собственному приложению, а не к системе с помощью LocalBroadcastManager :

Помощник для регистрации и отправки трансляций намерений на локальные объекты в рамках вашего процесса. Это имеет ряд преимуществ перед отправкой глобальных передач с помощью sendBroadcast (Intent):

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

Другие приложения не могут отправлять эти трансляции в ваше приложение, поэтому вам не нужно беспокоиться о наличии дыр в безопасности, которые они могут использовать.

Это более эффективно, чем отправка глобальной трансляции через систему.

Тем не менее, я по-прежнему рекомендую использовать подход «Служба» и локально привязывать и говорить через обработчик, когда это необходимо, для обновления компонентов пользовательского интерфейса.